codemirror-rails 5.9 → 5.10

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 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
+ });