codemirror-rails 5.9 → 5.10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dd70c9d501e50ef6240ec8c1ac5cb711069a101d
4
- data.tar.gz: d8350692868e90e6c20ee38c7f4357e394a31b94
3
+ metadata.gz: 7b8e61cc3f102bb8df59250814f8e085cbed2276
4
+ data.tar.gz: 94a4dc1242f2c4c35f5f3471b539b2e120a71776
5
5
  SHA512:
6
- metadata.gz: 7aeb9c1f1762dc429f13c5750e3e54fc4affe1f42826781f156746bff618072e80e03d84766c3c7c5f30b10e5ea490e84dbc9ce85e66379d90754077ea0659fe
7
- data.tar.gz: 9f375666986c29e6d43982137a47030c7f07ba6a2e9f129bdf27dee20ca01e32d5cd91bd9d24be84b58eba90596f44fe7a043dbd96cc4bb0440ec4eb167bbbf3
6
+ metadata.gz: cbe960c480acaa3d22287d67bee4d8a2f29ba62b5ff4e75b8c9db284fb0e419db0a693477a1a7d4e9dbc0aa67a1b1f985230a7ed4cfdc7b583be2928a15faaa4
7
+ data.tar.gz: a8a31612e7bd919fa5ddff87dee92782e97fe38bf57a838f0b12be52381682e2c49d4515bfa9b86ec539a24f0eb820b48f53b3c3c5cc7ee7344ab2f111f4288b
@@ -1,6 +1,6 @@
1
1
  module Codemirror
2
2
  module Rails
3
- VERSION = '5.9'
4
- CODEMIRROR_VERSION = '5.9'
3
+ VERSION = '5.10'
4
+ CODEMIRROR_VERSION = '5.10'
5
5
  end
6
6
  end
@@ -13,7 +13,7 @@
13
13
  else if (typeof define == "function" && define.amd) // AMD
14
14
  return define([], mod);
15
15
  else // Plain browser env
16
- this.CodeMirror = mod();
16
+ (this || window).CodeMirror = mod();
17
17
  })(function() {
18
18
  "use strict";
19
19
 
@@ -823,7 +823,7 @@
823
823
  // given line.
824
824
  function updateWidgetHeight(line) {
825
825
  if (line.widgets) for (var i = 0; i < line.widgets.length; ++i)
826
- line.widgets[i].height = line.widgets[i].node.offsetHeight;
826
+ line.widgets[i].height = line.widgets[i].node.parentNode.offsetHeight;
827
827
  }
828
828
 
829
829
  // Do a bulk-read of the DOM positions and sizes needed to draw the
@@ -1094,10 +1094,6 @@
1094
1094
  if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }
1095
1095
  }
1096
1096
 
1097
- function isReadOnly(cm) {
1098
- return cm.options.readOnly || cm.doc.cantEdit;
1099
- }
1100
-
1101
1097
  // This will be set to an array of strings when copying, so that,
1102
1098
  // when pasting, we know what kind of selections the copied text
1103
1099
  // was made out of.
@@ -1152,7 +1148,7 @@
1152
1148
  var pasted = e.clipboardData && e.clipboardData.getData("text/plain");
1153
1149
  if (pasted) {
1154
1150
  e.preventDefault();
1155
- if (!isReadOnly(cm) && !cm.options.disableInput)
1151
+ if (!cm.isReadOnly() && !cm.options.disableInput)
1156
1152
  runInOp(cm, function() { applyTextInput(cm, pasted, 0, null, "paste"); });
1157
1153
  return true;
1158
1154
  }
@@ -1255,7 +1251,7 @@
1255
1251
  });
1256
1252
 
1257
1253
  on(te, "paste", function(e) {
1258
- if (handlePaste(e, cm)) return true;
1254
+ if (signalDOMEvent(cm, e) || handlePaste(e, cm)) return
1259
1255
 
1260
1256
  cm.state.pasteIncoming = true;
1261
1257
  input.fastPoll();
@@ -1289,7 +1285,7 @@
1289
1285
  on(te, "copy", prepareCopyCut);
1290
1286
 
1291
1287
  on(display.scroller, "paste", function(e) {
1292
- if (eventInWidget(display, e)) return;
1288
+ if (eventInWidget(display, e) || signalDOMEvent(cm, e)) return;
1293
1289
  cm.state.pasteIncoming = true;
1294
1290
  input.focus();
1295
1291
  });
@@ -1423,7 +1419,7 @@
1423
1419
  // in which case reading its value would be expensive.
1424
1420
  if (this.contextMenuPending || !cm.state.focused ||
1425
1421
  (hasSelection(input) && !prevInput && !this.composing) ||
1426
- isReadOnly(cm) || cm.options.disableInput || cm.state.keySeq)
1422
+ cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq)
1427
1423
  return false;
1428
1424
 
1429
1425
  var text = input.value;
@@ -1574,7 +1570,9 @@
1574
1570
  var div = input.div = display.lineDiv;
1575
1571
  disableBrowserMagic(div);
1576
1572
 
1577
- on(div, "paste", function(e) { handlePaste(e, cm); })
1573
+ on(div, "paste", function(e) {
1574
+ if (!signalDOMEvent(cm, e)) handlePaste(e, cm);
1575
+ })
1578
1576
 
1579
1577
  on(div, "compositionstart", function(e) {
1580
1578
  var data = e.data;
@@ -1612,7 +1610,7 @@
1612
1610
 
1613
1611
  on(div, "input", function() {
1614
1612
  if (input.composing) return;
1615
- if (isReadOnly(cm) || !input.pollContent())
1613
+ if (cm.isReadOnly() || !input.pollContent())
1616
1614
  runInOp(input.cm, function() {regChange(cm);});
1617
1615
  });
1618
1616
 
@@ -1692,8 +1690,13 @@
1692
1690
  try { var rng = range(start.node, start.offset, end.offset, end.node); }
1693
1691
  catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
1694
1692
  if (rng) {
1695
- sel.removeAllRanges();
1696
- sel.addRange(rng);
1693
+ if (!gecko && this.cm.state.focused) {
1694
+ sel.collapse(start.node, start.offset);
1695
+ if (!rng.collapsed) sel.addRange(rng);
1696
+ } else {
1697
+ sel.removeAllRanges();
1698
+ sel.addRange(rng);
1699
+ }
1697
1700
  if (old && sel.anchorNode == null) sel.addRange(old);
1698
1701
  else if (gecko) this.startGracePeriod();
1699
1702
  }
@@ -1837,7 +1840,7 @@
1837
1840
  this.div.focus();
1838
1841
  },
1839
1842
  applyComposition: function(composing) {
1840
- if (isReadOnly(this.cm))
1843
+ if (this.cm.isReadOnly())
1841
1844
  operation(this.cm, regChange)(this.cm)
1842
1845
  else if (composing.data && composing.data != composing.startData)
1843
1846
  operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel);
@@ -1849,7 +1852,7 @@
1849
1852
 
1850
1853
  onKeyPress: function(e) {
1851
1854
  e.preventDefault();
1852
- if (!isReadOnly(this.cm))
1855
+ if (!this.cm.isReadOnly())
1853
1856
  operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0);
1854
1857
  },
1855
1858
 
@@ -2154,7 +2157,7 @@
2154
2157
 
2155
2158
  // Give beforeSelectionChange handlers a change to influence a
2156
2159
  // selection update.
2157
- function filterSelectionChange(doc, sel) {
2160
+ function filterSelectionChange(doc, sel, options) {
2158
2161
  var obj = {
2159
2162
  ranges: sel.ranges,
2160
2163
  update: function(ranges) {
@@ -2162,7 +2165,8 @@
2162
2165
  for (var i = 0; i < ranges.length; i++)
2163
2166
  this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
2164
2167
  clipPos(doc, ranges[i].head));
2165
- }
2168
+ },
2169
+ origin: options && options.origin
2166
2170
  };
2167
2171
  signal(doc, "beforeSelectionChange", doc, obj);
2168
2172
  if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj);
@@ -2188,7 +2192,7 @@
2188
2192
 
2189
2193
  function setSelectionNoUndo(doc, sel, options) {
2190
2194
  if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
2191
- sel = filterSelectionChange(doc, sel);
2195
+ sel = filterSelectionChange(doc, sel, options);
2192
2196
 
2193
2197
  var bias = options && options.bias ||
2194
2198
  (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
@@ -2222,8 +2226,9 @@
2222
2226
  var out;
2223
2227
  for (var i = 0; i < sel.ranges.length; i++) {
2224
2228
  var range = sel.ranges[i];
2225
- var newAnchor = skipAtomic(doc, range.anchor, bias, mayClear);
2226
- var newHead = skipAtomic(doc, range.head, bias, mayClear);
2229
+ var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i];
2230
+ var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear);
2231
+ var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear);
2227
2232
  if (out || newAnchor != range.anchor || newHead != range.head) {
2228
2233
  if (!out) out = sel.ranges.slice(0, i);
2229
2234
  out[i] = new Range(newAnchor, newHead);
@@ -2232,54 +2237,59 @@
2232
2237
  return out ? normalizeSelection(out, sel.primIndex) : sel;
2233
2238
  }
2234
2239
 
2235
- // Ensure a given position is not inside an atomic range.
2236
- function skipAtomic(doc, pos, bias, mayClear) {
2237
- var flipped = false, curPos = pos;
2238
- var dir = bias || 1;
2239
- doc.cantEdit = false;
2240
- search: for (;;) {
2241
- var line = getLine(doc, curPos.line);
2242
- if (line.markedSpans) {
2243
- for (var i = 0; i < line.markedSpans.length; ++i) {
2244
- var sp = line.markedSpans[i], m = sp.marker;
2245
- if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) &&
2246
- (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) {
2247
- if (mayClear) {
2248
- signal(m, "beforeCursorEnter");
2249
- if (m.explicitlyCleared) {
2250
- if (!line.markedSpans) break;
2251
- else {--i; continue;}
2252
- }
2253
- }
2254
- if (!m.atomic) continue;
2255
- var newPos = m.find(dir < 0 ? -1 : 1);
2256
- if (cmp(newPos, curPos) == 0) {
2257
- newPos.ch += dir;
2258
- if (newPos.ch < 0) {
2259
- if (newPos.line > doc.first) newPos = clipPos(doc, Pos(newPos.line - 1));
2260
- else newPos = null;
2261
- } else if (newPos.ch > line.text.length) {
2262
- if (newPos.line < doc.first + doc.size - 1) newPos = Pos(newPos.line + 1, 0);
2263
- else newPos = null;
2264
- }
2265
- if (!newPos) {
2266
- if (flipped) {
2267
- // Driven in a corner -- no valid cursor position found at all
2268
- // -- try again *with* clearing, if we didn't already
2269
- if (!mayClear) return skipAtomic(doc, pos, bias, true);
2270
- // Otherwise, turn off editing until further notice, and return the start of the doc
2271
- doc.cantEdit = true;
2272
- return Pos(doc.first, 0);
2273
- }
2274
- flipped = true; newPos = pos; dir = -dir;
2275
- }
2276
- }
2277
- curPos = newPos;
2278
- continue search;
2240
+ function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {
2241
+ var line = getLine(doc, pos.line);
2242
+ if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) {
2243
+ var sp = line.markedSpans[i], m = sp.marker;
2244
+ if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&
2245
+ (sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) {
2246
+ if (mayClear) {
2247
+ signal(m, "beforeCursorEnter");
2248
+ if (m.explicitlyCleared) {
2249
+ if (!line.markedSpans) break;
2250
+ else {--i; continue;}
2279
2251
  }
2280
2252
  }
2253
+ if (!m.atomic) continue;
2254
+
2255
+ if (oldPos) {
2256
+ var near = m.find(dir < 0 ? 1 : -1), diff;
2257
+ if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft) near = movePos(doc, near, -dir, line);
2258
+ if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))
2259
+ return skipAtomicInner(doc, near, pos, dir, mayClear);
2260
+ }
2261
+
2262
+ var far = m.find(dir < 0 ? -1 : 1);
2263
+ if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight) far = movePos(doc, far, dir, line);
2264
+ return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null;
2281
2265
  }
2282
- return curPos;
2266
+ }
2267
+ return pos;
2268
+ }
2269
+
2270
+ // Ensure a given position is not inside an atomic range.
2271
+ function skipAtomic(doc, pos, oldPos, bias, mayClear) {
2272
+ var dir = bias || 1;
2273
+ var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) ||
2274
+ (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) ||
2275
+ skipAtomicInner(doc, pos, oldPos, -dir, mayClear) ||
2276
+ (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true));
2277
+ if (!found) {
2278
+ doc.cantEdit = true;
2279
+ return Pos(doc.first, 0);
2280
+ }
2281
+ return found;
2282
+ }
2283
+
2284
+ function movePos(doc, pos, dir, line) {
2285
+ if (dir < 0 && pos.ch == 0) {
2286
+ if (pos.line > doc.first) return clipPos(doc, Pos(pos.line - 1));
2287
+ else return null;
2288
+ } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) {
2289
+ if (pos.line < doc.first + doc.size - 1) return Pos(pos.line + 1, 0);
2290
+ else return null;
2291
+ } else {
2292
+ return new Pos(pos.line, pos.ch + dir);
2283
2293
  }
2284
2294
  }
2285
2295
 
@@ -3608,7 +3618,7 @@
3608
3618
  }
3609
3619
 
3610
3620
  var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained;
3611
- if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) &&
3621
+ if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() &&
3612
3622
  type == "single" && (contained = sel.contains(start)) > -1 &&
3613
3623
  (cmp((contained = sel.ranges[contained]).from(), start) < 0 || start.xRel > 0) &&
3614
3624
  (cmp(contained.to(), start) > 0 || start.xRel < 0))
@@ -3832,7 +3842,7 @@
3832
3842
  e_preventDefault(e);
3833
3843
  if (ie) lastDrop = +new Date;
3834
3844
  var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
3835
- if (!pos || isReadOnly(cm)) return;
3845
+ if (!pos || cm.isReadOnly()) return;
3836
3846
  // Might be a file drop, in which case we simply extract the text
3837
3847
  // and insert it.
3838
3848
  if (files && files.length && window.FileReader && window.File) {
@@ -4071,7 +4081,7 @@
4071
4081
  cm.display.input.ensurePolled();
4072
4082
  var prevShift = cm.display.shift, done = false;
4073
4083
  try {
4074
- if (isReadOnly(cm)) cm.state.suppressEdits = true;
4084
+ if (cm.isReadOnly()) cm.state.suppressEdits = true;
4075
4085
  if (dropShift) cm.display.shift = false;
4076
4086
  done = bound(cm) != Pass;
4077
4087
  } finally {
@@ -4844,7 +4854,7 @@
4844
4854
  if (dir > 0 && !moveOnce(!first)) break;
4845
4855
  }
4846
4856
  }
4847
- var result = skipAtomic(doc, Pos(line, ch), origDir, true);
4857
+ var result = skipAtomic(doc, Pos(line, ch), pos, origDir, true);
4848
4858
  if (!possible) result.hitSide = true;
4849
4859
  return result;
4850
4860
  }
@@ -5232,6 +5242,7 @@
5232
5242
  signal(this, "overwriteToggle", this, this.state.overwrite);
5233
5243
  },
5234
5244
  hasFocus: function() { return this.display.input.getField() == activeElt(); },
5245
+ isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit); },
5235
5246
 
5236
5247
  scrollTo: methodOp(function(x, y) {
5237
5248
  if (x != null || y != null) resolveScrollToPos(this);
@@ -6668,7 +6679,7 @@
6668
6679
  parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;";
6669
6680
  removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle));
6670
6681
  }
6671
- return widget.height = widget.node.offsetHeight;
6682
+ return widget.height = widget.node.parentNode.offsetHeight;
6672
6683
  }
6673
6684
 
6674
6685
  function addLineWidget(doc, handle, node, options) {
@@ -7078,7 +7089,7 @@
7078
7089
  if (nextChange == pos) { // Update current marker set
7079
7090
  spanStyle = spanEndStyle = spanStartStyle = title = css = "";
7080
7091
  collapsed = null; nextChange = Infinity;
7081
- var foundBookmarks = [];
7092
+ var foundBookmarks = [], endStyles
7082
7093
  for (var j = 0; j < spans.length; ++j) {
7083
7094
  var sp = spans[j], m = sp.marker;
7084
7095
  if (m.type == "bookmark" && sp.from == pos && m.widgetNode) {
@@ -7091,7 +7102,7 @@
7091
7102
  if (m.className) spanStyle += " " + m.className;
7092
7103
  if (m.css) css = (css ? css + ";" : "") + m.css;
7093
7104
  if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
7094
- if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
7105
+ if (m.endStyle && sp.to == nextChange) (endStyles || (endStyles = [])).push(m.endStyle, sp.to)
7095
7106
  if (m.title && !title) title = m.title;
7096
7107
  if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
7097
7108
  collapsed = sp;
@@ -7099,6 +7110,9 @@
7099
7110
  nextChange = sp.from;
7100
7111
  }
7101
7112
  }
7113
+ if (endStyles) for (var j = 0; j < endStyles.length; j += 2)
7114
+ if (endStyles[j + 1] == nextChange) spanEndStyle += " " + endStyles[j]
7115
+
7102
7116
  if (collapsed && (collapsed.from || 0) == pos) {
7103
7117
  buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
7104
7118
  collapsed.marker, collapsed.from == null);
@@ -7446,10 +7460,11 @@
7446
7460
  extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);
7447
7461
  }),
7448
7462
  extendSelections: docMethodOp(function(heads, options) {
7449
- extendSelections(this, clipPosArray(this, heads, options));
7463
+ extendSelections(this, clipPosArray(this, heads), options);
7450
7464
  }),
7451
7465
  extendSelectionsBy: docMethodOp(function(f, options) {
7452
- extendSelections(this, map(this.sel.ranges, f), options);
7466
+ var heads = map(this.sel.ranges, f);
7467
+ extendSelections(this, clipPosArray(this, heads), options);
7453
7468
  }),
7454
7469
  setSelections: docMethodOp(function(ranges, primary, options) {
7455
7470
  if (!ranges.length) return;
@@ -8866,7 +8881,7 @@
8866
8881
 
8867
8882
  // THE END
8868
8883
 
8869
- CodeMirror.version = "5.9.0";
8884
+ CodeMirror.version = "5.10.0";
8870
8885
 
8871
8886
  return CodeMirror;
8872
8887
  });
@@ -295,13 +295,6 @@
295
295
  setTimeout(function(){cm.focus();}, 20);
296
296
  });
297
297
 
298
- if (completion.options.completeOnSingleClick)
299
- CodeMirror.on(hints, "mousemove", function(e) {
300
- var elt = getHintElement(hints, e.target || e.srcElement);
301
- if (elt && elt.hintId != null)
302
- widget.changeActive(elt.hintId);
303
- });
304
-
305
298
  CodeMirror.signal(data, "select", completions[0], hints.firstChild);
306
299
  return true;
307
300
  }
@@ -60,7 +60,7 @@
60
60
 
61
61
  function ensureState(states, name) {
62
62
  if (!states.hasOwnProperty(name))
63
- throw new Error("Undefined state " + name + "in simple mode");
63
+ throw new Error("Undefined state " + name + " in simple mode");
64
64
  }
65
65
 
66
66
  function toRegex(val, caret) {
@@ -16,7 +16,7 @@ CodeMirror.runMode = function(string, modespec, callback, options) {
16
16
  var ie = /MSIE \d/.test(navigator.userAgent);
17
17
  var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9);
18
18
 
19
- if (callback.nodeType == 1) {
19
+ if (callback.appendChild) {
20
20
  var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize;
21
21
  var node = callback, col = 0;
22
22
  node.innerHTML = "";
@@ -100,6 +100,9 @@
100
100
  elt.style.cssText = "position: absolute; right: 0px; width: " + Math.max(cm.display.barWidth - 1, 2) + "px; top: "
101
101
  + (top + this.buttonHeight) + "px; height: " + height + "px";
102
102
  elt.className = this.options.className;
103
+ if (ann.id) {
104
+ elt.setAttribute("annotation-id", ann.id);
105
+ }
103
106
  }
104
107
  this.div.textContent = "";
105
108
  this.div.appendChild(frag);
@@ -0,0 +1,49 @@
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: http://codemirror.net/LICENSE
3
+
4
+ // Defines jumpToLine command. Uses dialog.js if present.
5
+
6
+ (function(mod) {
7
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
8
+ mod(require("../../lib/codemirror"), require("../dialog/dialog"));
9
+ else if (typeof define == "function" && define.amd) // AMD
10
+ define(["../../lib/codemirror", "../dialog/dialog"], mod);
11
+ else // Plain browser env
12
+ mod(CodeMirror);
13
+ })(function(CodeMirror) {
14
+ "use strict";
15
+
16
+ function dialog(cm, text, shortText, deflt, f) {
17
+ if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true});
18
+ else f(prompt(shortText, deflt));
19
+ }
20
+
21
+ var jumpDialog =
22
+ 'Jump to line: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use line:column or scroll% syntax)</span>';
23
+
24
+ function interpretLine(cm, string) {
25
+ var num = Number(string)
26
+ if (/^[-+]/.test(string)) return cm.getCursor().line + num
27
+ else return num - 1
28
+ }
29
+
30
+ CodeMirror.commands.jumpToLine = function(cm) {
31
+ var cur = cm.getCursor();
32
+ dialog(cm, jumpDialog, "Jump to line:", (cur.line + 1) + ":" + cur.ch, function(posStr) {
33
+ if (!posStr) return;
34
+
35
+ var match;
36
+ if (match = /^\s*([\+\-]?\d+)\s*\:\s*(\d+)\s*$/.exec(posStr)) {
37
+ cm.setCursor(interpretLine(cm, match[1]), Number(match[2]))
38
+ } else if (match = /^\s*([\+\-]?\d+(\.\d+)?)\%\s*/.exec(posStr)) {
39
+ var line = Math.round(cm.lineCount() * Number(match[1]) / 100);
40
+ if (/^[-+]/.test(match[1])) line = cur.line + line + 1;
41
+ cm.setCursor(line - 1, cur.ch);
42
+ } else if (match = /^\s*\:?\s*([\+\-]?\d+)\s*/.exec(posStr)) {
43
+ cm.setCursor(interpretLine(cm, match[1]), cur.ch);
44
+ }
45
+ });
46
+ };
47
+
48
+ CodeMirror.keyMap["default"]["Alt-G"] = "jumpToLine";
49
+ });