codemirror-rails 2.34 → 2.35

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  module Codemirror
2
2
  module Rails
3
- VERSION = '2.34'
4
- CODEMIRROR_VERSION = '2.34'
3
+ VERSION = '2.35'
4
+ CODEMIRROR_VERSION = '2.35'
5
5
  end
6
6
  end
@@ -1,5 +1,5 @@
1
- // CodeMirror version 2.34
2
-
1
+ // CodeMirror version 2.35
2
+ //
3
3
  // All functions that need access to the editor's state live inside
4
4
  // the CodeMirror function. Below that, at the bottom of the file,
5
5
  // some utilities are defined.
@@ -77,7 +77,7 @@ window.CodeMirror = (function() {
77
77
  // Selection-related flags. shiftSelecting obviously tracks
78
78
  // whether the user is holding shift.
79
79
  var shiftSelecting, lastClick, lastDoubleClick, lastScrollTop = 0, draggingText,
80
- overwrite = false, suppressEdits = false;
80
+ overwrite = false, suppressEdits = false, pasteIncoming = false;
81
81
  // Variables used by startOperation/endOperation to track what
82
82
  // happened during the operation.
83
83
  var updateInput, userSelChange, changes, textChanged, selectionChanged,
@@ -130,7 +130,7 @@ window.CodeMirror = (function() {
130
130
  connect(scroller, "drop", operation(onDrop));
131
131
  }
132
132
  connect(scroller, "paste", function(){focusInput(); fastPoll();});
133
- connect(input, "paste", fastPoll);
133
+ connect(input, "paste", function(){pasteIncoming = true; fastPoll();});
134
134
  connect(input, "cut", operation(function(){
135
135
  if (!options.readOnly) replaceSelection("");
136
136
  }));
@@ -169,6 +169,7 @@ window.CodeMirror = (function() {
169
169
  else if (option == "lineWrapping" && oldVal != value) operation(wrappingChanged)();
170
170
  else if (option == "tabSize") updateDisplay(true);
171
171
  else if (option == "keyMap") keyMapChanged();
172
+ else if (option == "tabindex") input.tabIndex = value;
172
173
  if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber" ||
173
174
  option == "theme" || option == "lineNumberFormatter") {
174
175
  gutterChanged();
@@ -956,12 +957,13 @@ window.CodeMirror = (function() {
956
957
  while (same < l && prevInput[same] == text[same]) ++same;
957
958
  if (same < prevInput.length)
958
959
  sel.from = {line: sel.from.line, ch: sel.from.ch - (prevInput.length - same)};
959
- else if (overwrite && posEq(sel.from, sel.to))
960
+ else if (overwrite && posEq(sel.from, sel.to) && !pasteIncoming)
960
961
  sel.to = {line: sel.to.line, ch: Math.min(getLine(sel.to.line).text.length, sel.to.ch + (text.length - same))};
961
962
  replaceSelection(text.slice(same), "end");
962
963
  if (text.length > 1000) { input.value = prevInput = ""; }
963
964
  else prevInput = text;
964
965
  if (!nestedOperation) endOperation();
966
+ pasteIncoming = false;
965
967
  return true;
966
968
  }
967
969
  function resetInput(user) {
@@ -1418,7 +1420,7 @@ window.CodeMirror = (function() {
1418
1420
  var startChar = line.charAt(start);
1419
1421
  var check = isWordChar(startChar) ? isWordChar :
1420
1422
  /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);} :
1421
- function(ch) {return !/\s/.test(ch) && !isWordChar(ch);};
1423
+ function(ch) {return !/\s/.test(ch) && isWordChar(ch);};
1422
1424
  while (start > 0 && check(line.charAt(start - 1))) --start;
1423
1425
  while (end < line.length && check(line.charAt(end))) ++end;
1424
1426
  }
@@ -1462,6 +1464,7 @@ window.CodeMirror = (function() {
1462
1464
 
1463
1465
  if (indentString != curSpaceString)
1464
1466
  replaceRange(indentString, {line: n, ch: 0}, {line: n, ch: curSpaceString.length});
1467
+ line.stateAfter = null;
1465
1468
  }
1466
1469
 
1467
1470
  function loadMode() {
@@ -1507,18 +1510,17 @@ window.CodeMirror = (function() {
1507
1510
 
1508
1511
  function TextMarker(type, style) { this.lines = []; this.type = type; if (style) this.style = style; }
1509
1512
  TextMarker.prototype.clear = operation(function() {
1510
- var min = Infinity, max = -Infinity;
1513
+ var min, max;
1511
1514
  for (var i = 0; i < this.lines.length; ++i) {
1512
1515
  var line = this.lines[i];
1513
- var span = getMarkedSpanFor(line.markedSpans, this, true);
1514
- if (span.from != null || span.to != null) {
1515
- var lineN = lineNo(line);
1516
- min = Math.min(min, lineN); max = Math.max(max, lineN);
1517
- }
1516
+ var span = getMarkedSpanFor(line.markedSpans, this);
1517
+ if (span.from != null) min = lineNo(line);
1518
+ if (span.to != null) max = lineNo(line);
1519
+ line.markedSpans = removeMarkedSpan(line.markedSpans, span);
1518
1520
  }
1519
- if (min != Infinity)
1520
- changes.push({from: min, to: max + 1});
1521
+ if (min != null) changes.push({from: min, to: max + 1});
1521
1522
  this.lines.length = 0;
1523
+ this.explicitlyCleared = true;
1522
1524
  });
1523
1525
  TextMarker.prototype.find = function() {
1524
1526
  var from, to;
@@ -1545,7 +1547,7 @@ window.CodeMirror = (function() {
1545
1547
  var span = {from: curLine == from.line ? from.ch : null,
1546
1548
  to: curLine == to.line ? to.ch : null,
1547
1549
  marker: marker};
1548
- (line.markedSpans || (line.markedSpans = [])).push(span);
1550
+ line.markedSpans = (line.markedSpans || []).concat([span]);
1549
1551
  marker.lines.push(line);
1550
1552
  ++curLine;
1551
1553
  });
@@ -1556,8 +1558,9 @@ window.CodeMirror = (function() {
1556
1558
  function setBookmark(pos) {
1557
1559
  pos = clipPos(pos);
1558
1560
  var marker = new TextMarker("bookmark"), line = getLine(pos.line);
1561
+ history.addChange(pos.line, 1, [newHL(line.text, line.markedSpans)], true);
1559
1562
  var span = {from: pos.ch, to: pos.ch, marker: marker};
1560
- (line.markedSpans || (line.markedSpans = [])).push(span);
1563
+ line.markedSpans = (line.markedSpans || []).concat([span]);
1561
1564
  marker.lines.push(line);
1562
1565
  return marker;
1563
1566
  }
@@ -1646,8 +1649,6 @@ window.CodeMirror = (function() {
1646
1649
 
1647
1650
  function measureLine(line, ch) {
1648
1651
  if (ch == 0) return {top: 0, left: 0};
1649
- var wbr = options.lineWrapping && ch < line.text.length &&
1650
- spanAffectsWrapping.test(line.text.slice(ch - 1, ch + 1));
1651
1652
  var pre = lineContent(line, ch);
1652
1653
  removeChildrenAndAdd(measure, pre);
1653
1654
  var anchor = pre.anchor;
@@ -1980,6 +1981,7 @@ window.CodeMirror = (function() {
1980
1981
  if (extensions.propertyIsEnumerable(ext) &&
1981
1982
  !instance.propertyIsEnumerable(ext))
1982
1983
  instance[ext] = extensions[ext];
1984
+ for (var i = 0; i < initHooks.length; ++i) initHooks[i](instance);
1983
1985
  return instance;
1984
1986
  } // (end of function CodeMirror)
1985
1987
 
@@ -2077,6 +2079,9 @@ window.CodeMirror = (function() {
2077
2079
  extensions[name] = func;
2078
2080
  };
2079
2081
 
2082
+ var initHooks = [];
2083
+ CodeMirror.defineInitHook = function(f) {initHooks.push(f);};
2084
+
2080
2085
  var modeExtensions = CodeMirror.modeExtensions = {};
2081
2086
  CodeMirror.extendMode = function(mode, properties) {
2082
2087
  var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
@@ -2206,6 +2211,7 @@ window.CodeMirror = (function() {
2206
2211
  var name = keyNames[e_prop(event, "keyCode")];
2207
2212
  return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod";
2208
2213
  }
2214
+ CodeMirror.isModifierKey = isModifierKey;
2209
2215
 
2210
2216
  CodeMirror.fromTextArea = function(textarea, options) {
2211
2217
  if (!options) options = {};
@@ -2355,16 +2361,20 @@ window.CodeMirror = (function() {
2355
2361
  this.from = from; this.to = to; this.marker = marker;
2356
2362
  }
2357
2363
 
2358
- function getMarkedSpanFor(spans, marker, del) {
2364
+ function getMarkedSpanFor(spans, marker) {
2359
2365
  if (spans) for (var i = 0; i < spans.length; ++i) {
2360
2366
  var span = spans[i];
2361
- if (span.marker == marker) {
2362
- if (del) spans.splice(i, 1);
2363
- return span;
2364
- }
2367
+ if (span.marker == marker) return span;
2365
2368
  }
2366
2369
  }
2367
2370
 
2371
+ function removeMarkedSpan(spans, span) {
2372
+ var r;
2373
+ for (var i = 0; i < spans.length; ++i)
2374
+ if (spans[i] != span) (r || (r = [])).push(spans[i]);
2375
+ return r;
2376
+ }
2377
+
2368
2378
  function markedSpansBefore(old, startCh, endCh) {
2369
2379
  if (old) for (var i = 0, nw; i < old.length; ++i) {
2370
2380
  var span = old[i], marker = span.marker;
@@ -2448,7 +2458,15 @@ window.CodeMirror = (function() {
2448
2458
  // hl stands for history-line, a data structure that can be either a
2449
2459
  // string (line without markers) or a {text, markedSpans} object.
2450
2460
  function hlText(val) { return typeof val == "string" ? val : val.text; }
2451
- function hlSpans(val) { return typeof val == "string" ? null : val.markedSpans; }
2461
+ function hlSpans(val) {
2462
+ if (typeof val == "string") return null;
2463
+ var spans = val.markedSpans, out = null;
2464
+ for (var i = 0; i < spans.length; ++i) {
2465
+ if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); }
2466
+ else if (out) out.push(spans[i]);
2467
+ }
2468
+ return !out ? spans : out.length ? out : null;
2469
+ }
2452
2470
  function newHL(text, spans) { return spans ? {text: text, markedSpans: spans} : text; }
2453
2471
 
2454
2472
  function detachMarkedSpans(line) {
@@ -2584,13 +2602,17 @@ window.CodeMirror = (function() {
2584
2602
  span = function(html, text, style) {
2585
2603
  var l = text.length;
2586
2604
  if (wrapAt >= outPos && wrapAt < outPos + l) {
2587
- if (wrapAt > outPos) {
2588
- span_(html, text.slice(0, wrapAt - outPos), style);
2605
+ var cut = wrapAt - outPos;
2606
+ if (cut) {
2607
+ span_(html, text.slice(0, cut), style);
2589
2608
  // See comment at the definition of spanAffectsWrapping
2590
- if (compensateForWrapping) html.appendChild(elt("wbr"));
2609
+ if (compensateForWrapping) {
2610
+ var view = text.slice(cut - 1, cut + 1);
2611
+ if (spanAffectsWrapping.test(view)) html.appendChild(elt("wbr"));
2612
+ else if (!ie_lt8 && /\w\w/.test(view)) html.appendChild(document.createTextNode("\u200d"));
2613
+ }
2591
2614
  }
2592
2615
  html.appendChild(anchor);
2593
- var cut = wrapAt - outPos;
2594
2616
  span_(anchor, opera ? text.slice(cut, cut + 1) : text.slice(cut), style);
2595
2617
  if (opera) span_(html, text.slice(cut + 1), style);
2596
2618
  wrapAt--;
@@ -2874,7 +2896,7 @@ window.CodeMirror = (function() {
2874
2896
  var time = +new Date, cur = lst(this.done), last = cur && lst(cur);
2875
2897
  var dtime = time - this.time;
2876
2898
 
2877
- if (this.compound && cur && !this.closed) {
2899
+ if (cur && !this.closed && this.compound) {
2878
2900
  cur.push({start: start, added: added, old: old});
2879
2901
  } else if (dtime > 400 || !last || this.closed ||
2880
2902
  last.start > start + old.length || last.start + last.added < start) {
@@ -3081,7 +3103,7 @@ window.CodeMirror = (function() {
3081
3103
  return -1;
3082
3104
  }
3083
3105
  function isWordChar(ch) {
3084
- return /\w/.test(ch) || ch.toUpperCase() != ch.toLowerCase();
3106
+ return /\w/.test(ch) || ch.toUpperCase() != ch.toLowerCase() || /[\u4E00-\u9FA5]/.test(ch);
3085
3107
  }
3086
3108
 
3087
3109
  // See if "".split is the broken IE version, if so, provide an
@@ -3137,7 +3159,7 @@ window.CodeMirror = (function() {
3137
3159
  for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i;
3138
3160
  })();
3139
3161
 
3140
- CodeMirror.version = "2.34";
3162
+ CodeMirror.version = "2.35";
3141
3163
 
3142
3164
  return CodeMirror;
3143
3165
  })();
@@ -318,13 +318,12 @@
318
318
  };
319
319
 
320
320
  // standard mode switching
321
- iterList(["d", "t", "T", "f", "F", "c", "r"],
322
- function (ch) {
323
- CodeMirror.keyMap.vim[toCombo(ch)] = function (cm) {
324
- cm.setOption("keyMap", "vim-prefix-" + ch);
325
- emptyBuffer();
326
- };
327
- });
321
+ iterList(["d", "t", "T", "f", "F", "c", "r"], function (ch) {
322
+ CodeMirror.keyMap.vim[toCombo(ch)] = function (cm) {
323
+ cm.setOption("keyMap", "vim-prefix-" + ch);
324
+ emptyBuffer();
325
+ };
326
+ });
328
327
 
329
328
  function addCountBindings(keyMap) {
330
329
  // Add bindings for number keys
@@ -645,7 +644,7 @@
645
644
  };
646
645
 
647
646
  // Map our movement actions each operator and non-operational movement
648
- motionList.forEach(function(key, index, array) {
647
+ iterList(motionList, function(key, index, array) {
649
648
  CodeMirror.keyMap['vim-prefix-d'][key] = function(cm) {
650
649
  // Get our selected range
651
650
  var start = cm.getCursor();
@@ -695,7 +694,7 @@
695
694
  });
696
695
 
697
696
  var nums = [1,2,3,4,5,6,7,8,9];
698
- nums.forEach(function(key, index, array) {
697
+ iterList(nums, function(key, index, array) {
699
698
  CodeMirror.keyMap['vim'][key] = function (cm) {
700
699
  reptTimes = (reptTimes * 10) + key;
701
700
  };
@@ -713,7 +712,7 @@
713
712
  // Create our keymaps for each operator and make xa and xi where x is an operator
714
713
  // change to the corrosponding keymap
715
714
  var operators = ['d', 'y', 'c'];
716
- operators.forEach(function(key, index, array) {
715
+ iterList(operators, function(key, index, array) {
717
716
  CodeMirror.keyMap['vim-prefix-'+key+'a'] = {
718
717
  auto: 'vim', nofallthrough: true, style: "fat-cursor"
719
718
  };
@@ -140,6 +140,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
140
140
  },
141
141
 
142
142
  indent: function(state, textAfter) {
143
+ if (state.tokenize == tokenComment) return CodeMirror.Pass;
143
144
  if (state.tokenize != tokenBase && state.tokenize != null) return 0;
144
145
  var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
145
146
  if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev;
@@ -228,7 +228,7 @@ CodeMirror.defineMode("css", function(config) {
228
228
  else if (/[,+>*\/]/.test(ch)) {
229
229
  return ret(null, "select-op");
230
230
  }
231
- else if (ch == "." && stream.match(/^\w+/)) {
231
+ else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
232
232
  return ret("qualifier", type);
233
233
  }
234
234
  else if (ch == ":") {
@@ -1,150 +1,94 @@
1
1
  CodeMirror.defineMode("gfm", function(config, parserConfig) {
2
- var mdMode = CodeMirror.getMode(config, "markdown");
3
- var aliases = {
4
- html: "htmlmixed",
5
- js: "javascript",
6
- json: "application/json",
7
- c: "text/x-csrc",
8
- "c++": "text/x-c++src",
9
- java: "text/x-java",
10
- csharp: "text/x-csharp",
11
- "c#": "text/x-csharp"
12
- };
13
-
14
- // make this lazy so that we don't need to load GFM last
15
- var getMode = (function () {
16
- var i, modes = {}, mimes = {}, mime;
17
-
18
- var list = CodeMirror.listModes();
19
- for (i = 0; i < list.length; i++) {
20
- modes[list[i]] = list[i];
21
- }
22
- var mimesList = CodeMirror.listMIMEs();
23
- for (i = 0; i < mimesList.length; i++) {
24
- mime = mimesList[i].mime;
25
- mimes[mime] = mimesList[i].mime;
26
- }
27
-
28
- for (var a in aliases) {
29
- if (aliases[a] in modes || aliases[a] in mimes)
30
- modes[a] = aliases[a];
31
- }
32
-
33
- return function (lang) {
34
- return modes[lang] ? CodeMirror.getMode(config, modes[lang]) : null;
35
- };
36
- }());
37
-
38
- function markdown(stream, state) {
39
- // intercept fenced code blocks
40
- if (stream.sol() && stream.match(/^```([\w+#]*)/)) {
41
- // try switching mode
42
- state.localMode = getMode(RegExp.$1);
43
- if (state.localMode)
44
- state.localState = state.localMode.startState();
45
-
46
- state.token = local;
47
- return 'code';
48
- }
49
-
50
- return mdMode.token(stream, state.mdState);
51
- }
52
-
53
- function local(stream, state) {
54
- if (stream.sol() && stream.match(/^```/)) {
55
- state.localMode = state.localState = null;
56
- state.token = markdown;
57
- return 'code';
58
- }
59
- else if (state.localMode) {
60
- return state.localMode.token(stream, state.localState);
61
- } else {
62
- stream.skipToEnd();
63
- return 'code';
64
- }
65
- }
66
-
67
- // custom handleText to prevent emphasis in the middle of a word
68
- // and add autolinking
69
- function handleText(stream, mdState) {
70
- var match;
71
- if (stream.match(/^\w+:\/\/\S+/)) {
72
- return 'link';
73
- }
74
- if (stream.match(/^[^\[*\\<>` _][^\[*\\<>` ]*[^\[*\\<>` _]/)) {
75
- return mdMode.getType(mdState);
76
- }
77
- if (match = stream.match(/^[^\[*\\<>` ]+/)) {
78
- var word = match[0];
79
- if (word[0] === '_' && word[word.length-1] === '_') {
80
- stream.backUp(word.length);
81
- return undefined;
82
- }
83
- return mdMode.getType(mdState);
84
- }
85
- if (stream.eatSpace()) {
86
- return null;
87
- }
2
+ var codeDepth = 0;
3
+ function blankLine(state) {
4
+ state.code = false;
5
+ return null;
88
6
  }
89
-
90
- return {
7
+ var gfmOverlay = {
91
8
  startState: function() {
92
- var mdState = mdMode.startState();
93
- mdState.text = handleText;
94
- return {token: markdown, mode: "markdown", mdState: mdState,
95
- localMode: null, localState: null};
9
+ return {
10
+ code: false,
11
+ codeBlock: false,
12
+ ateSpace: false
13
+ };
96
14
  },
97
-
98
- copyState: function(state) {
99
- return {token: state.token, mdState: CodeMirror.copyState(mdMode, state.mdState),
100
- localMode: state.localMode,
101
- localState: state.localMode ? CodeMirror.copyState(state.localMode, state.localState) : null};
15
+ copyState: function(s) {
16
+ return {
17
+ code: s.code,
18
+ codeBlock: s.codeBlock,
19
+ ateSpace: s.ateSpace
20
+ };
102
21
  },
103
-
104
22
  token: function(stream, state) {
105
- /* Parse GFM double bracket links */
106
- var ch;
107
- if ((ch = stream.peek()) != undefined && ch == '[') {
108
- stream.next(); // Advance the stream
109
-
110
- /* Only handle double bracket links */
111
- if ((ch = stream.peek()) == undefined || ch != '[') {
112
- stream.backUp(1);
113
- return state.token(stream, state);
114
- }
115
-
116
- while ((ch = stream.next()) != undefined && ch != ']') {}
117
-
118
- if (ch == ']' && (ch = stream.next()) != undefined && ch == ']')
119
- return 'link';
120
-
121
- /* If we did not find the second ']' */
122
- stream.backUp(1);
123
- }
124
-
125
- /* Match GFM latex formulas, as well as latex formulas within '$' */
126
- if (stream.match(/^\$[^\$]+\$/)) {
127
- return "string";
23
+ // Hack to prevent formatting override inside code blocks (block and inline)
24
+ if (state.codeBlock) {
25
+ if (stream.match(/^```/)) {
26
+ state.codeBlock = false;
27
+ return null;
128
28
  }
129
-
130
- if (stream.match(/^\\\((.*?)\\\)/)) {
131
- return "string";
132
- }
133
-
134
- if (stream.match(/^\$\$[^\$]+\$\$/)) {
135
- return "string";
29
+ stream.skipToEnd();
30
+ return null;
31
+ }
32
+ if (stream.sol()) {
33
+ state.code = false;
34
+ }
35
+ if (stream.sol() && stream.match(/^```/)) {
36
+ stream.skipToEnd();
37
+ state.codeBlock = true;
38
+ return null;
39
+ }
40
+ // If this block is changed, it may need to be updated in Markdown mode
41
+ if (stream.peek() === '`') {
42
+ stream.next();
43
+ var before = stream.pos;
44
+ stream.eatWhile('`');
45
+ var difference = 1 + stream.pos - before;
46
+ if (!state.code) {
47
+ codeDepth = difference;
48
+ state.code = true;
49
+ } else {
50
+ if (difference === codeDepth) { // Must be exact
51
+ state.code = false;
52
+ }
136
53
  }
137
-
138
- if (stream.match(/^\\\[(.*?)\\\]/)) {
139
- return "string";
54
+ return null;
55
+ } else if (state.code) {
56
+ stream.next();
57
+ return null;
58
+ }
59
+ // Check if space. If so, links can be formatted later on
60
+ if (stream.eatSpace()) {
61
+ state.ateSpace = true;
62
+ return null;
63
+ }
64
+ if (stream.sol() || state.ateSpace) {
65
+ state.ateSpace = false;
66
+ if(stream.match(/^(?:[a-zA-Z0-9\-_]+\/)?(?:[a-zA-Z0-9\-_]+@)?(?:[a-f0-9]{7,40}\b)/)) {
67
+ // User/Project@SHA
68
+ // User@SHA
69
+ // SHA
70
+ return "link";
71
+ } else if (stream.match(/^(?:[a-zA-Z0-9\-_]+\/)?(?:[a-zA-Z0-9\-_]+)?#[0-9]+\b/)) {
72
+ // User/Project#Num
73
+ // User#Num
74
+ // #Num
75
+ return "link";
140
76
  }
141
-
142
- return state.token(stream, state);
77
+ }
78
+ if (stream.match(/^((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/i)) {
79
+ // URLs
80
+ // Taken from http://daringfireball.net/2010/07/improved_regex_for_matching_urls
81
+ return "link";
82
+ }
83
+ stream.next();
84
+ return null;
143
85
  },
144
-
145
- innerMode: function(state) {
146
- if (state.token == markdown) return {state: state.mdState, mode: mdMode};
147
- else return {state: state.localState, mode: state.localMode};
148
- }
86
+ blankLine: blankLine
149
87
  };
150
- }, "markdown");
88
+ CodeMirror.defineMIME("gfmBase", {
89
+ name: "markdown",
90
+ underscoresBreakWords: false,
91
+ fencedCodeBlocks: true
92
+ });
93
+ return CodeMirror.overlayMode(CodeMirror.getMode(config, "gfmBase"), gfmOverlay);
94
+ });
@@ -70,3 +70,4 @@ CodeMirror.defineMode("htmlembedded", function(config, parserConfig) {
70
70
  CodeMirror.defineMIME("application/x-ejs", { name: "htmlembedded", scriptingModeSpec:"javascript"});
71
71
  CodeMirror.defineMIME("application/x-aspx", { name: "htmlembedded", scriptingModeSpec:"text/x-csharp"});
72
72
  CodeMirror.defineMIME("application/x-jsp", { name: "htmlembedded", scriptingModeSpec:"text/x-java"});
73
+ CodeMirror.defineMIME("application/x-erb", { name: "htmlembedded", scriptingModeSpec:"ruby"});
@@ -1,6 +1,9 @@
1
+ // TODO actually recognize syntax of TypeScript constructs
2
+
1
3
  CodeMirror.defineMode("javascript", function(config, parserConfig) {
2
4
  var indentUnit = config.indentUnit;
3
5
  var jsonMode = parserConfig.json;
6
+ var isTS = parserConfig.typescript;
4
7
 
5
8
  // Tokenizer
6
9
 
@@ -8,7 +11,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
8
11
  function kw(type) {return {type: type, style: "keyword"};}
9
12
  var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
10
13
  var operator = kw("operator"), atom = {type: "atom", style: "atom"};
11
- return {
14
+
15
+ var jsKeywords = {
12
16
  "if": A, "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
13
17
  "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C,
14
18
  "var": kw("var"), "const": kw("var"), "let": kw("var"),
@@ -17,6 +21,35 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
17
21
  "in": operator, "typeof": operator, "instanceof": operator,
18
22
  "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom
19
23
  };
24
+
25
+ // Extend the 'normal' keywords with the TypeScript language extensions
26
+ if (isTS) {
27
+ var type = {type: "variable", style: "variable-3"};
28
+ var tsKeywords = {
29
+ // object-like things
30
+ "interface": kw("interface"),
31
+ "class": kw("class"),
32
+ "extends": kw("extends"),
33
+ "constructor": kw("constructor"),
34
+
35
+ // scope modifiers
36
+ "public": kw("public"),
37
+ "private": kw("private"),
38
+ "protected": kw("protected"),
39
+ "static": kw("static"),
40
+
41
+ "super": kw("super"),
42
+
43
+ // types
44
+ "string": type, "number": type, "bool": type, "any": type
45
+ };
46
+
47
+ for (var attr in tsKeywords) {
48
+ jsKeywords[attr] = tsKeywords[attr];
49
+ }
50
+ }
51
+
52
+ return jsKeywords;
20
53
  }();
21
54
 
22
55
  var isOperatorChar = /[+\-*&%=<>!?|]/;
@@ -66,7 +99,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
66
99
  stream.skipToEnd();
67
100
  return ret("comment", "comment");
68
101
  }
69
- else if (state.reAllowed) {
102
+ else if (state.lastType == "operator" || state.lastType == "keyword c" ||
103
+ /^[\[{}\(,;:]$/.test(state.lastType)) {
70
104
  nextUntilUnescaped(stream, "/");
71
105
  stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
72
106
  return ret("regexp", "string-2");
@@ -87,7 +121,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
87
121
  else {
88
122
  stream.eatWhile(/[\w\$_]/);
89
123
  var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
90
- return (known && state.kwAllowed) ? ret(known.type, known.style, word) :
124
+ return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
91
125
  ret("variable", "variable", word);
92
126
  }
93
127
  }
@@ -275,19 +309,30 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
275
309
  if (type == "}") return cont();
276
310
  return pass(statement, block);
277
311
  }
312
+ function maybetype(type) {
313
+ if (type == ":") return cont(typedef);
314
+ return pass();
315
+ }
316
+ function typedef(type) {
317
+ if (type == "variable"){cx.marked = "variable-3"; return cont();}
318
+ return pass();
319
+ }
278
320
  function vardef1(type, value) {
279
- if (type == "variable"){register(value); return cont(vardef2);}
280
- return cont();
321
+ if (type == "variable") {
322
+ register(value);
323
+ return isTS ? cont(maybetype, vardef2) : cont(vardef2);
324
+ }
325
+ return pass();
281
326
  }
282
327
  function vardef2(type, value) {
283
328
  if (value == "=") return cont(expression, vardef2);
284
329
  if (type == ",") return cont(vardef1);
285
330
  }
286
331
  function forspec1(type) {
287
- if (type == "var") return cont(vardef1, forspec2);
288
- if (type == ";") return pass(forspec2);
332
+ if (type == "var") return cont(vardef1, expect(";"), forspec2);
333
+ if (type == ";") return cont(forspec2);
289
334
  if (type == "variable") return cont(formaybein);
290
- return pass(forspec2);
335
+ return cont(forspec2);
291
336
  }
292
337
  function formaybein(type, value) {
293
338
  if (value == "in") return cont(expression);
@@ -306,7 +351,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
306
351
  if (type == "(") return cont(pushlex(")"), pushcontext, commasep(funarg, ")"), poplex, statement, popcontext);
307
352
  }
308
353
  function funarg(type, value) {
309
- if (type == "variable") {register(value); return cont();}
354
+ if (type == "variable") {register(value); return isTS ? cont(maybetype) : cont();}
310
355
  }
311
356
 
312
357
  // Interface
@@ -315,8 +360,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
315
360
  startState: function(basecolumn) {
316
361
  return {
317
362
  tokenize: jsTokenBase,
318
- reAllowed: true,
319
- kwAllowed: true,
363
+ lastType: null,
320
364
  cc: [],
321
365
  lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
322
366
  localVars: parserConfig.localVars,
@@ -334,19 +378,21 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
334
378
  if (stream.eatSpace()) return null;
335
379
  var style = state.tokenize(stream, state);
336
380
  if (type == "comment") return style;
337
- state.reAllowed = !!(type == "operator" || type == "keyword c" || type.match(/^[\[{}\(,;:]$/));
338
- state.kwAllowed = type != '.';
381
+ state.lastType = type;
339
382
  return parseJS(state, style, type, content, stream);
340
383
  },
341
384
 
342
385
  indent: function(state, textAfter) {
386
+ if (state.tokenize == jsTokenComment) return CodeMirror.Pass;
343
387
  if (state.tokenize != jsTokenBase) return 0;
344
388
  var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
345
389
  if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
346
390
  var type = lexical.type, closing = firstChar == type;
347
- if (type == "vardef") return lexical.indented + 4;
391
+ if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? 4 : 0);
348
392
  else if (type == "form" && firstChar == "{") return lexical.indented;
349
- else if (type == "stat" || type == "form") return lexical.indented + indentUnit;
393
+ else if (type == "form") return lexical.indented + indentUnit;
394
+ else if (type == "stat")
395
+ return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? indentUnit : 0);
350
396
  else if (lexical.info == "switch" && !closing)
351
397
  return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
352
398
  else if (lexical.align) return lexical.column + (closing ? 0 : 1);
@@ -359,3 +405,5 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
359
405
 
360
406
  CodeMirror.defineMIME("text/javascript", "javascript");
361
407
  CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
408
+ CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
409
+ CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
@@ -64,7 +64,7 @@ CodeMirror.defineMode("lua", function(config, parserConfig) {
64
64
  function normal(stream, state) {
65
65
  var ch = stream.next();
66
66
  if (ch == "-" && stream.eat("-")) {
67
- if (stream.eat("["))
67
+ if (stream.eat("[") && stream.eat("["))
68
68
  return (state.cur = bracketed(readBracket(stream), "comment"))(stream, state);
69
69
  stream.skipToEnd();
70
70
  return "comment";
@@ -2,6 +2,46 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
2
2
 
3
3
  var htmlFound = CodeMirror.mimeModes.hasOwnProperty("text/html");
4
4
  var htmlMode = CodeMirror.getMode(cmCfg, htmlFound ? "text/html" : "text/plain");
5
+ var aliases = {
6
+ html: "htmlmixed",
7
+ js: "javascript",
8
+ json: "application/json",
9
+ c: "text/x-csrc",
10
+ "c++": "text/x-c++src",
11
+ java: "text/x-java",
12
+ csharp: "text/x-csharp",
13
+ "c#": "text/x-csharp"
14
+ };
15
+
16
+ var getMode = (function () {
17
+ var i, modes = {}, mimes = {}, mime;
18
+
19
+ var list = CodeMirror.listModes();
20
+ for (i = 0; i < list.length; i++) {
21
+ modes[list[i]] = list[i];
22
+ }
23
+ var mimesList = CodeMirror.listMIMEs();
24
+ for (i = 0; i < mimesList.length; i++) {
25
+ mime = mimesList[i].mime;
26
+ mimes[mime] = mimesList[i].mime;
27
+ }
28
+
29
+ for (var a in aliases) {
30
+ if (aliases[a] in modes || aliases[a] in mimes)
31
+ modes[a] = aliases[a];
32
+ }
33
+
34
+ return function (lang) {
35
+ return modes[lang] ? CodeMirror.getMode(cmCfg, modes[lang]) : null;
36
+ };
37
+ }());
38
+
39
+ // Should underscores in words open/close em/strong?
40
+ if (modeCfg.underscoresBreakWords === undefined)
41
+ modeCfg.underscoresBreakWords = true;
42
+
43
+ // Turn on fenced code blocks? ("```" to start/end)
44
+ if (modeCfg.fencedCodeBlocks === undefined) modeCfg.fencedCodeBlocks = false;
5
45
 
6
46
  var codeDepth = 0;
7
47
  var prevLineHasContent = false
@@ -12,6 +52,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
12
52
  , quote = 'quote'
13
53
  , list = 'string'
14
54
  , hr = 'hr'
55
+ , image = 'tag'
15
56
  , linkinline = 'link'
16
57
  , linkemail = 'link'
17
58
  , linktext = 'link'
@@ -24,7 +65,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
24
65
  , ulRE = /^[*\-+]\s+/
25
66
  , olRE = /^[0-9]+\.\s+/
26
67
  , headerRE = /^(?:\={1,}|-{1,})$/
27
- , textRE = /^[^\[*_\\<>` "'(]+/;
68
+ , textRE = /^[^!\[\]*_\\<>` "'(]+/;
28
69
 
29
70
  function switchInline(stream, state, f) {
30
71
  state.f = state.inline = f;
@@ -42,8 +83,6 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
42
83
  function blankLine(state) {
43
84
  // Reset linkTitle state
44
85
  state.linkTitle = false;
45
- // Reset CODE state
46
- state.code = false;
47
86
  // Reset EM state
48
87
  state.em = false;
49
88
  // Reset STRONG state
@@ -58,7 +97,6 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
58
97
  }
59
98
 
60
99
  function blockNormal(stream, state) {
61
- var match;
62
100
 
63
101
  if (state.list !== false && state.indentationDiff >= 0) { // Continued list
64
102
  if (state.indentationDiff < 4) { // Only adjust indentation if *not* a code block
@@ -84,9 +122,15 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
84
122
  return switchInline(stream, state, footnoteLink);
85
123
  } else if (stream.match(hrRE, true)) {
86
124
  return hr;
87
- } else if (match = stream.match(ulRE, true) || stream.match(olRE, true)) {
125
+ } else if (stream.match(ulRE, true) || stream.match(olRE, true)) {
88
126
  state.indentation += 4;
89
127
  state.list = true;
128
+ } else if (modeCfg.fencedCodeBlocks && stream.match(/^```([\w+#]*)/, true)) {
129
+ // try switching mode
130
+ state.localMode = getMode(RegExp.$1);
131
+ if (state.localMode) state.localState = state.localMode.startState();
132
+ switchBlock(stream, state, local);
133
+ return code;
90
134
  }
91
135
 
92
136
  return switchInline(stream, state, state.inline);
@@ -106,6 +150,30 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
106
150
  return style;
107
151
  }
108
152
 
153
+ function local(stream, state) {
154
+ if (stream.sol() && stream.match(/^```/, true)) {
155
+ state.localMode = state.localState = null;
156
+ state.f = inlineNormal;
157
+ state.block = blockNormal;
158
+ return code;
159
+ } else if (state.localMode) {
160
+ return state.localMode.token(stream, state.localState);
161
+ } else {
162
+ stream.skipToEnd();
163
+ return code;
164
+ }
165
+ }
166
+
167
+ function codeBlock(stream, state) {
168
+ if(stream.match(codeBlockRE, true)){
169
+ state.f = inlineNormal;
170
+ state.block = blockNormal;
171
+ switchInline(stream, state, state.inline);
172
+ return code;
173
+ }
174
+ stream.skipToEnd();
175
+ return code;
176
+ }
109
177
 
110
178
  // Inline
111
179
  function getType(state) {
@@ -114,6 +182,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
114
182
  if (state.strong) { styles.push(state.em ? emstrong : strong); }
115
183
  else if (state.em) { styles.push(em); }
116
184
 
185
+ if (state.linkText) { styles.push(linktext); }
186
+
117
187
  if (state.code) { styles.push(code); }
118
188
 
119
189
  if (state.header) { styles.push(header); }
@@ -161,6 +231,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
161
231
  }
162
232
  }
163
233
 
234
+ // If this block is changed, it may need to be updated in GFM mode
164
235
  if (ch === '`') {
165
236
  var t = getType(state);
166
237
  var before = stream.pos;
@@ -181,8 +252,22 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
181
252
  return getType(state);
182
253
  }
183
254
 
184
- if (ch === '[' && stream.match(/.*\] ?(?:\(|\[)/, false)) {
185
- return switchInline(stream, state, linkText);
255
+ if (ch === '!' && stream.match(/\[.*\] ?(?:\(|\[)/, false)) {
256
+ stream.match(/\[.*\]/);
257
+ state.inline = state.f = linkHref;
258
+ return image;
259
+ }
260
+
261
+ if (ch === '[' && stream.match(/.*\](\(| ?\[)/, false)) {
262
+ state.linkText = true;
263
+ return getType(state);
264
+ }
265
+
266
+ if (ch === ']' && state.linkText) {
267
+ var type = getType(state);
268
+ state.linkText = false;
269
+ state.inline = state.f = linkHref;
270
+ return type;
186
271
  }
187
272
 
188
273
  if (ch === '<' && stream.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/, true)) {
@@ -210,8 +295,20 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
210
295
  return "tag";
211
296
  }
212
297
 
298
+ var ignoreUnderscore = false;
299
+ if (!modeCfg.underscoresBreakWords) {
300
+ if (ch === '_' && stream.peek() !== '_' && stream.match(/(\w)/, false)) {
301
+ var prevPos = stream.pos - 2;
302
+ if (prevPos >= 0) {
303
+ var prevCh = stream.string.charAt(prevPos);
304
+ if (prevCh !== '_' && prevCh.match(/(\w)/, false)) {
305
+ ignoreUnderscore = true;
306
+ }
307
+ }
308
+ }
309
+ }
213
310
  var t = getType(state);
214
- if (ch === '*' || ch === '_') {
311
+ if (ch === '*' || (ch === '_' && !ignoreUnderscore)) {
215
312
  if (state.strong === ch && stream.eat(ch)) { // Remove STRONG
216
313
  state.strong = false;
217
314
  return t;
@@ -238,18 +335,6 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
238
335
  return getType(state);
239
336
  }
240
337
 
241
- function linkText(stream, state) {
242
- while (!stream.eol()) {
243
- var ch = stream.next();
244
- if (ch === '\\') stream.next();
245
- if (ch === ']') {
246
- state.inline = state.f = linkHref;
247
- return linktext;
248
- }
249
- }
250
- return linktext;
251
- }
252
-
253
338
  function linkHref(stream, state) {
254
339
  // Check if space, and return NULL if so (to avoid marking the space)
255
340
  if(stream.eatSpace()){
@@ -287,15 +372,16 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
287
372
  return linkhref;
288
373
  }
289
374
 
375
+ var savedInlineRE = [];
290
376
  function inlineRE(endChar) {
291
- if (!inlineRE[endChar]) {
377
+ if (!savedInlineRE[endChar]) {
292
378
  // Escape endChar for RegExp (taken from http://stackoverflow.com/a/494122/526741)
293
379
  endChar = (endChar+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
294
380
  // Match any non-endChar, escaped character, as well as the closing
295
381
  // endChar.
296
- inlineRE[endChar] = new RegExp('^(?:[^\\\\]+?|\\\\.)*?(' + endChar + ')');
382
+ savedInlineRE[endChar] = new RegExp('^(?:[^\\\\]|\\\\.)*?(' + endChar + ')');
297
383
  }
298
- return inlineRE[endChar];
384
+ return savedInlineRE[endChar];
299
385
  }
300
386
 
301
387
  function inlineElement(type, endChar, next) {
@@ -309,6 +395,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
309
395
 
310
396
  return {
311
397
  startState: function() {
398
+ prevLineHasContent = false;
399
+ thisLineHasContent = false;
312
400
  return {
313
401
  f: blockNormal,
314
402
 
@@ -318,6 +406,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
318
406
 
319
407
  inline: inlineNormal,
320
408
  text: handleText,
409
+
410
+ linkText: false,
321
411
  linkTitle: false,
322
412
  em: false,
323
413
  strong: false,
@@ -334,6 +424,9 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
334
424
  block: s.block,
335
425
  htmlState: CodeMirror.copyState(htmlMode, s.htmlState),
336
426
  indentation: s.indentation,
427
+
428
+ localMode: s.localMode,
429
+ localState: s.localMode ? CodeMirror.copyState(s.localMode, s.localState) : null,
337
430
 
338
431
  inline: s.inline,
339
432
  text: s.text,
@@ -362,9 +455,15 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
362
455
 
363
456
  // Reset state.header
364
457
  state.header = false;
458
+
459
+ // Reset state.code
460
+ state.code = false;
365
461
 
366
462
  state.f = state.block;
367
463
  var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length;
464
+ var difference = Math.floor((indentation - state.indentation) / 4) * 4;
465
+ if (difference > 4) difference = 4;
466
+ indentation = state.indentation + difference;
368
467
  state.indentationDiff = indentation - state.indentation;
369
468
  state.indentation = indentation;
370
469
  if (indentation > 0) { return null; }
@@ -49,6 +49,11 @@ CodeMirror.overlayMode = CodeMirror.overlayParser = function(base, overlay, comb
49
49
  },
50
50
  electricChars: base.electricChars,
51
51
 
52
- innerMode: function(state) { return {state: state.base, mode: base}; }
52
+ innerMode: function(state) { return {state: state.base, mode: base}; },
53
+
54
+ blankLine: function(state) {
55
+ if (base.blankLine) base.blankLine(state.base);
56
+ if (overlay.blankLine) overlay.blankLine(state.overlay);
57
+ }
53
58
  };
54
59
  };
@@ -1,6 +1,6 @@
1
1
  CodeMirror.runMode = function(string, modespec, callback, options) {
2
2
  function esc(str) {
3
- return str.replace(/[<&]/, function(ch) { return ch == "<" ? "&lt;" : "&amp;"; });
3
+ return str.replace(/[<&]/g, function(ch) { return ch == "<" ? "&lt;" : "&amp;"; });
4
4
  }
5
5
 
6
6
  var mode = CodeMirror.getMode(CodeMirror.defaults, modespec);
@@ -17,14 +17,14 @@
17
17
  query.lastIndex = 0;
18
18
  var line = cm.getLine(pos.line).slice(0, pos.ch), match = query.exec(line), start = 0;
19
19
  while (match) {
20
- start += match.index;
21
- line = line.slice(match.index);
20
+ start += match.index + 1;
21
+ line = line.slice(start);
22
22
  query.lastIndex = 0;
23
23
  var newmatch = query.exec(line);
24
24
  if (newmatch) match = newmatch;
25
25
  else break;
26
- start++;
27
26
  }
27
+ start--;
28
28
  } else {
29
29
  query.lastIndex = pos.ch;
30
30
  var line = cm.getLine(pos.line), match = query.exec(line),
@@ -25,7 +25,10 @@
25
25
  editor.replaceRange(str, result.from, result.to);
26
26
  }
27
27
  // When there is only one completion, use it directly.
28
- if (completions.length == 1) {insert(completions[0]); return true;}
28
+ if (options.completeSingle && completions.length == 1) {
29
+ insert(completions[0]);
30
+ return true;
31
+ }
29
32
 
30
33
  // Build the select widget
31
34
  var complete = document.createElement("div");
@@ -41,7 +44,7 @@
41
44
  }
42
45
  sel.firstChild.selected = true;
43
46
  sel.size = Math.min(10, completions.length);
44
- var pos = editor.cursorCoords();
47
+ var pos = options.alignWithWord ? editor.charCoords(result.from) : editor.cursorCoords();
45
48
  complete.style.left = pos.x + "px";
46
49
  complete.style.top = pos.yBot + "px";
47
50
  document.body.appendChild(complete);
@@ -71,7 +74,7 @@
71
74
  if (code == 13) {CodeMirror.e_stop(event); pick();}
72
75
  // Escape
73
76
  else if (code == 27) {CodeMirror.e_stop(event); close(); editor.focus();}
74
- else if (code != 38 && code != 40 && code != 33 && code != 34) {
77
+ else if (code != 38 && code != 40 && code != 33 && code != 34 && !CodeMirror.isModifierKey(event)) {
75
78
  close(); editor.focus();
76
79
  // Pass the event to the CodeMirror instance so that it can handle things like backspace properly.
77
80
  editor.triggerOnKeyDown(event);
@@ -92,6 +95,8 @@
92
95
  };
93
96
  CodeMirror.simpleHint.defaults = {
94
97
  closeOnBackspace: true,
95
- closeOnTokenChange: false
98
+ closeOnTokenChange: false,
99
+ completeSingle: true,
100
+ alignWithWord: true
96
101
  };
97
102
  })();
@@ -80,6 +80,7 @@
80
80
  word-wrap: normal;
81
81
  line-height: inherit;
82
82
  color: inherit;
83
+ overflow: visible;
83
84
  }
84
85
 
85
86
  .CodeMirror-wrap pre {
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: codemirror-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: '2.34'
4
+ version: '2.35'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-13 00:00:00.000000000Z
12
+ date: 2012-10-27 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: railties
16
- requirement: &2165230860 !ruby/object:Gem::Requirement
16
+ requirement: &2165649660 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '3.0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2165230860
24
+ version_requirements: *2165649660
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rails
27
- requirement: &2165230340 !ruby/object:Gem::Requirement
27
+ requirement: &2165648920 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '3.0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *2165230340
35
+ version_requirements: *2165648920
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: sqlite3
38
- requirement: &2165229960 !ruby/object:Gem::Requirement
38
+ requirement: &2165647960 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *2165229960
46
+ version_requirements: *2165647960
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: minitest
49
- requirement: &2165229320 !ruby/object:Gem::Requirement
49
+ requirement: &2165647440 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *2165229320
57
+ version_requirements: *2165647440
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: capybara
60
- requirement: &2165228760 !ruby/object:Gem::Requirement
60
+ requirement: &2165647020 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,7 +65,7 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *2165228760
68
+ version_requirements: *2165647020
69
69
  description: This gem provides CodeMirror assets for your Rails 3 application.
70
70
  email: nathan@fixler.org
71
71
  executables: []