codemirror-rails 3.20 → 3.21

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.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/lib/codemirror/rails/version.rb +2 -2
  3. data/vendor/assets/javascripts/codemirror.js +240 -135
  4. data/vendor/assets/javascripts/codemirror/addons/comment/comment.js +6 -2
  5. data/vendor/assets/javascripts/codemirror/addons/comment/continuecomment.js +1 -1
  6. data/vendor/assets/javascripts/codemirror/addons/dialog/dialog.js +1 -0
  7. data/vendor/assets/javascripts/codemirror/addons/edit/closebrackets.js +5 -3
  8. data/vendor/assets/javascripts/codemirror/addons/edit/closetag.js +10 -6
  9. data/vendor/assets/javascripts/codemirror/addons/edit/continuelist.js +2 -0
  10. data/vendor/assets/javascripts/codemirror/addons/edit/matchbrackets.js +1 -1
  11. data/vendor/assets/javascripts/codemirror/addons/fold/comment-fold.js +3 -1
  12. data/vendor/assets/javascripts/codemirror/addons/fold/foldcode.js +13 -2
  13. data/vendor/assets/javascripts/codemirror/addons/fold/foldgutter.js +1 -1
  14. data/vendor/assets/javascripts/codemirror/addons/fold/indent-fold.js +2 -2
  15. data/vendor/assets/javascripts/codemirror/addons/fold/xml-fold.js +6 -0
  16. data/vendor/assets/javascripts/codemirror/addons/hint/anyword-hint.js +3 -5
  17. data/vendor/assets/javascripts/codemirror/addons/hint/css-hint.js +29 -33
  18. data/vendor/assets/javascripts/codemirror/addons/hint/javascript-hint.js +1 -1
  19. data/vendor/assets/javascripts/codemirror/addons/hint/pig-hint.js +1 -1
  20. data/vendor/assets/javascripts/codemirror/addons/hint/python-hint.js +1 -5
  21. data/vendor/assets/javascripts/codemirror/addons/hint/show-hint.js +58 -9
  22. data/vendor/assets/javascripts/codemirror/addons/hint/sql-hint.js +58 -17
  23. data/vendor/assets/javascripts/codemirror/addons/hint/xml-hint.js +5 -5
  24. data/vendor/assets/javascripts/codemirror/addons/lint/lint.js +1 -1
  25. data/vendor/assets/javascripts/codemirror/addons/merge/merge.js +6 -1
  26. data/vendor/assets/javascripts/codemirror/addons/mode/multiplex.js +5 -3
  27. data/vendor/assets/javascripts/codemirror/addons/runmode/runmode-standalone.js +26 -11
  28. data/vendor/assets/javascripts/codemirror/addons/runmode/runmode.js +1 -1
  29. data/vendor/assets/javascripts/codemirror/addons/runmode/runmode.node.js +22 -11
  30. data/vendor/assets/javascripts/codemirror/addons/search/search.js +22 -9
  31. data/vendor/assets/javascripts/codemirror/addons/search/searchcursor.js +48 -24
  32. data/vendor/assets/javascripts/codemirror/addons/selection/active-line.js +15 -9
  33. data/vendor/assets/javascripts/codemirror/addons/tern/tern.js +3 -3
  34. data/vendor/assets/javascripts/codemirror/addons/wrap/hardwrap.js +21 -9
  35. data/vendor/assets/javascripts/codemirror/keymaps/emacs.js +12 -1
  36. data/vendor/assets/javascripts/codemirror/keymaps/vim.js +110 -28
  37. data/vendor/assets/javascripts/codemirror/modes/clike.js +28 -9
  38. data/vendor/assets/javascripts/codemirror/modes/coffeescript.js +3 -4
  39. data/vendor/assets/javascripts/codemirror/modes/css.js +341 -297
  40. data/vendor/assets/javascripts/codemirror/modes/erlang.js +302 -179
  41. data/vendor/assets/javascripts/codemirror/modes/gfm.js +10 -5
  42. data/vendor/assets/javascripts/codemirror/modes/gherkin.js +45 -50
  43. data/vendor/assets/javascripts/codemirror/modes/haml.js +0 -4
  44. data/vendor/assets/javascripts/codemirror/modes/haskell.js +5 -3
  45. data/vendor/assets/javascripts/codemirror/modes/htmlembedded.js +0 -2
  46. data/vendor/assets/javascripts/codemirror/modes/htmlmixed.js +0 -2
  47. data/vendor/assets/javascripts/codemirror/modes/javascript.js +43 -30
  48. data/vendor/assets/javascripts/codemirror/modes/jinja2.js +13 -3
  49. data/vendor/assets/javascripts/codemirror/modes/less.js +7 -6
  50. data/vendor/assets/javascripts/codemirror/modes/markdown.js +231 -45
  51. data/vendor/assets/javascripts/codemirror/modes/{ocaml.js → mllike.js} +88 -13
  52. data/vendor/assets/javascripts/codemirror/modes/pegjs.js +5 -9
  53. data/vendor/assets/javascripts/codemirror/modes/php.js +6 -7
  54. data/vendor/assets/javascripts/codemirror/modes/python.js +6 -0
  55. data/vendor/assets/javascripts/codemirror/modes/r.js +5 -1
  56. data/vendor/assets/javascripts/codemirror/modes/rpm-spec.js +1 -1
  57. data/vendor/assets/javascripts/codemirror/modes/ruby.js +3 -1
  58. data/vendor/assets/javascripts/codemirror/modes/smalltalk.js +4 -2
  59. data/vendor/assets/javascripts/codemirror/modes/smartymixed.js +0 -2
  60. data/vendor/assets/javascripts/codemirror/modes/sql.js +5 -4
  61. data/vendor/assets/javascripts/codemirror/modes/xml.js +87 -100
  62. data/vendor/assets/stylesheets/codemirror/themes/mbo.css +1 -1
  63. data/vendor/assets/stylesheets/codemirror/themes/midnight.css +1 -1
  64. data/vendor/assets/stylesheets/codemirror/themes/pastel-on-dark.css +49 -0
  65. data/vendor/assets/stylesheets/codemirror/themes/the-matrix.css +1 -1
  66. metadata +3 -2
@@ -96,8 +96,9 @@
96
96
  for (var i = start; i <= end; ++i) {
97
97
  var line = self.getLine(i);
98
98
  var found = line.indexOf(lineString);
99
+ if (found > -1 && !/comment/.test(self.getTokenTypeAt(Pos(i, found + 1)))) found = -1;
99
100
  if (found == -1 && (i != end || i == start) && nonWS.test(line)) break lineComment;
100
- if (i != start && found > -1 && nonWS.test(line.slice(0, found))) break lineComment;
101
+ if (found > -1 && nonWS.test(line.slice(0, found))) break lineComment;
101
102
  lines.push(line);
102
103
  }
103
104
  self.operation(function() {
@@ -124,7 +125,10 @@
124
125
  endLine = self.getLine(--end);
125
126
  close = endLine.lastIndexOf(endString);
126
127
  }
127
- if (open == -1 || close == -1) return false;
128
+ if (open == -1 || close == -1 ||
129
+ !/comment/.test(self.getTokenTypeAt(Pos(start, open + 1))) ||
130
+ !/comment/.test(self.getTokenTypeAt(Pos(end, close + 1))))
131
+ return false;
128
132
 
129
133
  self.operation(function() {
130
134
  self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)),
@@ -5,7 +5,7 @@
5
5
 
6
6
  function continueComment(cm) {
7
7
  var pos = cm.getCursor(), token = cm.getTokenAt(pos);
8
- if (token.type != "comment") return CodeMirror.Pass;
8
+ if (token.type != "comment" || cm.getOption("disableInput")) return CodeMirror.Pass;
9
9
  var mode = CodeMirror.innerMode(cm.getMode(), token.state).mode;
10
10
 
11
11
  var insert;
@@ -35,6 +35,7 @@
35
35
  }
36
36
  var inp = dialog.getElementsByTagName("input")[0], button;
37
37
  if (inp) {
38
+ if (options && options.value) inp.value = options.value;
38
39
  CodeMirror.on(inp, "keydown", function(e) {
39
40
  if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; }
40
41
  if (e.keyCode == 13 || e.keyCode == 27) {
@@ -28,7 +28,7 @@
28
28
  var map = {
29
29
  name : "autoCloseBrackets",
30
30
  Backspace: function(cm) {
31
- if (cm.somethingSelected()) return CodeMirror.Pass;
31
+ if (cm.somethingSelected() || cm.getOption("disableInput")) return CodeMirror.Pass;
32
32
  var cur = cm.getCursor(), around = charsAround(cm, cur);
33
33
  if (around && pairs.indexOf(around) % 2 == 0)
34
34
  cm.replaceRange("", CodeMirror.Pos(cur.line, cur.ch - 1), CodeMirror.Pos(cur.line, cur.ch + 1));
@@ -49,7 +49,8 @@
49
49
  else cm.execCommand("goCharRight");
50
50
  }
51
51
  map["'" + left + "'"] = function(cm) {
52
- if (left == "'" && cm.getTokenAt(cm.getCursor()).type == "comment")
52
+ if (left == "'" && cm.getTokenAt(cm.getCursor()).type == "comment" ||
53
+ cm.getOption("disableInput"))
53
54
  return CodeMirror.Pass;
54
55
  if (cm.somethingSelected()) return surround(cm);
55
56
  if (left == right && maybeOverwrite(cm) != CodeMirror.Pass) return;
@@ -70,7 +71,8 @@
70
71
  function buildExplodeHandler(pairs) {
71
72
  return function(cm) {
72
73
  var cur = cm.getCursor(), around = charsAround(cm, cur);
73
- if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
74
+ if (!around || pairs.indexOf(around) % 2 != 0 || cm.getOption("disableInput"))
75
+ return CodeMirror.Pass;
74
76
  cm.operation(function() {
75
77
  var newPos = CodeMirror.Pos(cur.line + 1, 0);
76
78
  cm.replaceSelection("\n\n", {anchor: newPos, head: newPos}, "+input");
@@ -43,7 +43,7 @@
43
43
  function autoCloseGT(cm) {
44
44
  var pos = cm.getCursor(), tok = cm.getTokenAt(pos);
45
45
  var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
46
- if (inner.mode.name != "xml" || !state.tagName) return CodeMirror.Pass;
46
+ if (inner.mode.name != "xml" || !state.tagName || cm.getOption("disableInput")) return CodeMirror.Pass;
47
47
 
48
48
  var opt = cm.getOption("autoCloseTags"), html = inner.mode.configuration == "html";
49
49
  var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose);
@@ -53,10 +53,13 @@
53
53
  if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch);
54
54
  var lowerTagName = tagName.toLowerCase();
55
55
  // Don't process the '>' at the end of an end-tag or self-closing tag
56
- if (tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) ||
56
+ if (!tagName ||
57
+ tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) ||
57
58
  tok.type == "tag" && state.type == "closeTag" ||
58
59
  tok.string.indexOf("/") == (tok.string.length - 1) || // match something like <someTagName />
59
- dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1)
60
+ dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 ||
61
+ CodeMirror.scanForClosingTag && CodeMirror.scanForClosingTag(cm, pos, tagName,
62
+ Math.min(cm.lastLine() + 1, pos.line + 50)))
60
63
  return CodeMirror.Pass;
61
64
 
62
65
  var doIndent = indentTags && indexOf(indentTags, lowerTagName) > -1;
@@ -64,8 +67,8 @@
64
67
  cm.replaceSelection(">" + (doIndent ? "\n\n" : "") + "</" + tagName + ">",
65
68
  {head: curPos, anchor: curPos});
66
69
  if (doIndent) {
67
- cm.indentLine(pos.line + 1);
68
- cm.indentLine(pos.line + 2);
70
+ cm.indentLine(pos.line + 1, null, true);
71
+ cm.indentLine(pos.line + 2, null);
69
72
  }
70
73
  }
71
74
 
@@ -73,7 +76,8 @@
73
76
  var pos = cm.getCursor(), tok = cm.getTokenAt(pos);
74
77
  var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
75
78
  if (tok.type == "string" || tok.string.charAt(0) != "<" ||
76
- tok.start != pos.ch - 1 || inner.mode.name != "xml")
79
+ tok.start != pos.ch - 1 || inner.mode.name != "xml" ||
80
+ cm.getOption("disableInput"))
77
81
  return CodeMirror.Pass;
78
82
 
79
83
  var tagName = state.context && state.context.tagName;
@@ -5,6 +5,8 @@
5
5
  unorderedBullets = '*+-';
6
6
 
7
7
  CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) {
8
+ if (cm.getOption("disableInput")) return CodeMirror.Pass;
9
+
8
10
  var pos = cm.getCursor(),
9
11
  inList = cm.getStateAfter(pos.line).list !== false,
10
12
  match;
@@ -54,7 +54,7 @@
54
54
  var one = cm.markText(found.from, Pos(found.from.line, found.from.ch + 1), {className: style});
55
55
  var two = found.to && cm.markText(found.to, Pos(found.to.line, found.to.ch + 1), {className: style});
56
56
  // Kludge to work around the IE bug from issue #1193, where text
57
- // input stops going to the textare whever this fires.
57
+ // input stops going to the textarea whenever this fires.
58
58
  if (ie_lt8 && cm.state.focused) cm.display.input.focus();
59
59
  var clear = function() {
60
60
  cm.operation(function() { one.clear(); two && two.clear(); });
@@ -1,4 +1,6 @@
1
- CodeMirror.registerHelper("fold", "comment", function(cm, start) {
1
+ CodeMirror.registerGlobalHelper("fold", "comment", function(mode) {
2
+ return mode.blockCommentStart && mode.blockCommentEnd;
3
+ }, function(cm, start) {
2
4
  var mode = cm.getModeAt(start), startToken = mode.blockCommentStart, endToken = mode.blockCommentEnd;
3
5
  if (!startToken || !endToken) return;
4
6
  var line = start.line, lineText = cm.getLine(line);
@@ -3,8 +3,7 @@
3
3
 
4
4
  function doFold(cm, pos, options, force) {
5
5
  var finder = options && (options.call ? options : options.rangeFinder);
6
- if (!finder) finder = cm.getHelper(pos, "fold");
7
- if (!finder) return;
6
+ if (!finder) finder = CodeMirror.fold.auto;
8
7
  if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0);
9
8
  var minSize = options && options.minFoldSize || 0;
10
9
 
@@ -63,6 +62,10 @@
63
62
  doFold(this, pos, options, force);
64
63
  });
65
64
 
65
+ CodeMirror.commands.fold = function(cm) {
66
+ cm.foldCode(cm.getCursor());
67
+ };
68
+
66
69
  CodeMirror.registerHelper("fold", "combine", function() {
67
70
  var funcs = Array.prototype.slice.call(arguments, 0);
68
71
  return function(cm, start) {
@@ -72,4 +75,12 @@
72
75
  }
73
76
  };
74
77
  });
78
+
79
+ CodeMirror.registerHelper("fold", "auto", function(cm, start) {
80
+ var helpers = cm.getHelpers(start, "fold");
81
+ for (var i = 0; i < helpers.length; i++) {
82
+ var cur = helpers[i](cm, start);
83
+ if (cur) return cur;
84
+ }
85
+ });
75
86
  })();
@@ -62,7 +62,7 @@
62
62
  if (isFolded(cm, cur)) {
63
63
  mark = marker(opts.indicatorFolded);
64
64
  } else {
65
- var pos = Pos(cur, 0), func = opts.rangeFinder || cm.getHelper(pos, "fold");
65
+ var pos = Pos(cur, 0), func = opts.rangeFinder || CodeMirror.fold.auto;
66
66
  var range = func && func(cm, pos);
67
67
  if (range && range.from.line + 1 < range.to.line)
68
68
  mark = marker(opts.indicatorOpen);
@@ -1,8 +1,8 @@
1
1
  CodeMirror.registerHelper("fold", "indent", function(cm, start) {
2
2
  var tabSize = cm.getOption("tabSize"), firstLine = cm.getLine(start.line);
3
3
  if (!/\S/.test(firstLine)) return;
4
- var getIndent = function(lineNum) {
5
- return CodeMirror.countColumn(lineNum, null, tabSize);
4
+ var getIndent = function(line) {
5
+ return CodeMirror.countColumn(line, null, tabSize);
6
6
  };
7
7
  var myIndent = getIndent(firstLine);
8
8
  var lastLineInFold = null;
@@ -164,4 +164,10 @@
164
164
  if (close) return {open: open, close: close};
165
165
  }
166
166
  };
167
+
168
+ // Used by addon/edit/closetag.js
169
+ CodeMirror.scanForClosingTag = function(cm, pos, name, end) {
170
+ var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null);
171
+ return !!findMatchingClose(iter, name);
172
+ };
167
173
  })();
@@ -13,22 +13,20 @@
13
13
  var curWord = start != end && curLine.slice(start, end);
14
14
 
15
15
  var list = [], seen = {};
16
- function scan(dir) {
16
+ var re = new RegExp(word.source, "g");
17
+ for (var dir = -1; dir <= 1; dir += 2) {
17
18
  var line = cur.line, end = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir;
18
19
  for (; line != end; line += dir) {
19
20
  var text = editor.getLine(line), m;
20
- var re = new RegExp(word.source, "g");
21
21
  while (m = re.exec(text)) {
22
22
  if (line == cur.line && m[0] === curWord) continue;
23
- if ((!curWord || m[0].indexOf(curWord) == 0) && !seen.hasOwnProperty(m[0])) {
23
+ if ((!curWord || m[0].lastIndexOf(curWord, 0) == 0) && !Object.prototype.hasOwnProperty.call(seen, m[0])) {
24
24
  seen[m[0]] = true;
25
25
  list.push(m[0]);
26
26
  }
27
27
  }
28
28
  }
29
29
  }
30
- scan(-1);
31
- scan(1);
32
30
  return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)};
33
31
  });
34
32
  })();
@@ -1,50 +1,46 @@
1
1
  (function () {
2
2
  "use strict";
3
3
 
4
- function getHints(cm) {
4
+ var pseudoClasses = {link: 1, visited: 1, active: 1, hover: 1, focus: 1,
5
+ "first-letter": 1, "first-line": 1, "first-child": 1,
6
+ before: 1, after: 1, lang: 1};
7
+
8
+ CodeMirror.registerHelper("hint", "css", function(cm) {
5
9
  var cur = cm.getCursor(), token = cm.getTokenAt(cur);
6
10
  var inner = CodeMirror.innerMode(cm.getMode(), token.state);
7
11
  if (inner.mode.name != "css") return;
8
12
 
9
- // If it's not a 'word-style' token, ignore the token.
10
- if (!/^[\w$_-]*$/.test(token.string)) {
11
- token = {
12
- start: cur.ch, end: cur.ch, string: "", state: token.state,
13
- type: null
14
- };
15
- var stack = token.state.stack;
16
- var lastToken = stack && stack.length > 0 ? stack[stack.length - 1] : "";
17
- if (token.string == ":" || lastToken.indexOf("property") == 0)
18
- token.type = "variable";
19
- else if (token.string == "{" || lastToken.indexOf("rule") == 0)
20
- token.type = "property";
13
+ var word = token.string, start = token.start, end = token.end;
14
+ if (/[^\w$_-]/.test(word)) {
15
+ word = ""; start = end = cur.ch;
21
16
  }
22
17
 
23
- if (!token.type)
24
- return;
25
-
26
18
  var spec = CodeMirror.resolveMode("text/css");
27
- var keywords = null;
28
- if (token.type.indexOf("property") == 0)
29
- keywords = spec.propertyKeywords;
30
- else if (token.type.indexOf("variable") == 0)
31
- keywords = spec.valueKeywords;
32
-
33
- if (!keywords)
34
- return;
35
19
 
36
20
  var result = [];
37
- for (var name in keywords) {
38
- if (name.indexOf(token.string) == 0 /* > -1 */)
39
- result.push(name);
21
+ function add(keywords) {
22
+ for (var name in keywords)
23
+ if (!word || name.lastIndexOf(word, 0) == 0)
24
+ result.push(name);
40
25
  }
41
26
 
42
- return {
27
+ var st = token.state.state;
28
+ if (st == "pseudo" || token.type == "variable-3") {
29
+ add(pseudoClasses);
30
+ } else if (st == "block" || st == "maybeprop") {
31
+ add(spec.propertyKeywords);
32
+ } else if (st == "prop" || st == "parens" || st == "at" || st == "params") {
33
+ add(spec.valueKeywords);
34
+ add(spec.colorKeywords);
35
+ } else if (st == "media" || st == "media_parens") {
36
+ add(spec.mediaTypes);
37
+ add(spec.mediaFeatures);
38
+ }
39
+
40
+ if (result.length) return {
43
41
  list: result,
44
- from: CodeMirror.Pos(cur.line, token.start),
45
- to: CodeMirror.Pos(cur.line, token.end)
42
+ from: CodeMirror.Pos(cur.line, start),
43
+ to: CodeMirror.Pos(cur.line, end)
46
44
  };
47
- }
48
-
49
- CodeMirror.registerHelper("hint", "css", getHints);
45
+ });
50
46
  })();
@@ -87,7 +87,7 @@
87
87
  function getCompletions(token, context, keywords, options) {
88
88
  var found = [], start = token.string;
89
89
  function maybeAdd(str) {
90
- if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str);
90
+ if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str);
91
91
  }
92
92
  function gatherCompletions(obj) {
93
93
  if (typeof obj == "string") forEach(stringProps, maybeAdd);
@@ -84,7 +84,7 @@
84
84
  function getCompletions(token, context) {
85
85
  var found = [], start = token.string;
86
86
  function maybeAdd(str) {
87
- if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str);
87
+ if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str);
88
88
  }
89
89
 
90
90
  function gatherCompletions(obj) {
@@ -31,10 +31,6 @@
31
31
 
32
32
  var completionList = getCompletions(token, context);
33
33
  completionList = completionList.sort();
34
- //prevent autocomplete for last word, instead show dropdown with one word
35
- if(completionList.length == 1) {
36
- completionList.push(" ");
37
- }
38
34
 
39
35
  return {list: completionList,
40
36
  from: CodeMirror.Pos(cur.line, token.start),
@@ -66,7 +62,7 @@
66
62
  function getCompletions(token, context) {
67
63
  var found = [], start = token.string;
68
64
  function maybeAdd(str) {
69
- if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str);
65
+ if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str);
70
66
  }
71
67
 
72
68
  function gatherCompletions(_obj) {
@@ -7,8 +7,10 @@
7
7
  CodeMirror.showHint = function(cm, getHints, options) {
8
8
  // We want a single cursor position.
9
9
  if (cm.somethingSelected()) return;
10
- if (getHints == null) getHints = cm.getHelper(cm.getCursor(), "hint");
11
- if (getHints == null) return;
10
+ if (getHints == null) {
11
+ if (options && options.async) return;
12
+ else getHints = CodeMirror.hint.auto;
13
+ }
12
14
 
13
15
  if (cm.state.completionActive) cm.state.completionActive.close();
14
16
 
@@ -45,6 +47,7 @@
45
47
  var completion = data.list[i];
46
48
  if (completion.hint) completion.hint(this.cm, data, completion);
47
49
  else this.cm.replaceRange(getText(completion), data.from, data.to);
50
+ CodeMirror.signal(data, "pick", completion);
48
51
  this.close();
49
52
  },
50
53
 
@@ -61,10 +64,15 @@
61
64
  this.widget = new Widget(this, data);
62
65
  CodeMirror.signal(data, "shown");
63
66
 
64
- var debounce = null, completion = this, finished;
67
+ var debounce = 0, completion = this, finished;
65
68
  var closeOn = this.options.closeCharacters || /[\s()\[\]{};:>,]/;
66
69
  var startPos = this.cm.getCursor(), startLen = this.cm.getLine(startPos.line).length;
67
70
 
71
+ var requestAnimationFrame = window.requestAnimationFrame || function(fn) {
72
+ return setTimeout(fn, 1000/60);
73
+ };
74
+ var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;
75
+
68
76
  function done() {
69
77
  if (finished) return;
70
78
  finished = true;
@@ -88,15 +96,22 @@
88
96
  completion.widget = new Widget(completion, data);
89
97
  }
90
98
 
99
+ function clearDebounce() {
100
+ if (debounce) {
101
+ cancelAnimationFrame(debounce);
102
+ debounce = 0;
103
+ }
104
+ }
105
+
91
106
  function activity() {
92
- clearTimeout(debounce);
107
+ clearDebounce();
93
108
  var pos = completion.cm.getCursor(), line = completion.cm.getLine(pos.line);
94
109
  if (pos.line != startPos.line || line.length - pos.ch != startLen - startPos.ch ||
95
110
  pos.ch < startPos.ch || completion.cm.somethingSelected() ||
96
111
  (pos.ch && closeOn.test(line.charAt(pos.ch - 1)))) {
97
112
  completion.close();
98
113
  } else {
99
- debounce = setTimeout(update, 170);
114
+ debounce = requestAnimationFrame(update);
100
115
  if (completion.widget) completion.widget.close();
101
116
  }
102
117
  }
@@ -143,9 +158,9 @@
143
158
  return ourMap;
144
159
  }
145
160
 
146
- function getHintElement(stopAt, el) {
147
- while (el && el != stopAt) {
148
- if (el.nodeName.toUpperCase() === "LI") return el;
161
+ function getHintElement(hintsElement, el) {
162
+ while (el && el != hintsElement) {
163
+ if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el;
149
164
  el = el.parentNode;
150
165
  }
151
166
  }
@@ -232,7 +247,10 @@
232
247
 
233
248
  CodeMirror.on(hints, "click", function(e) {
234
249
  var t = getHintElement(hints, e.target || e.srcElement);
235
- if (t && t.hintId != null) widget.changeActive(t.hintId);
250
+ if (t && t.hintId != null) {
251
+ widget.changeActive(t.hintId);
252
+ if (options.completeOnSingleClick) widget.pick();
253
+ }
236
254
  });
237
255
 
238
256
  CodeMirror.on(hints, "mousedown", function() {
@@ -283,4 +301,35 @@
283
301
  return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1;
284
302
  }
285
303
  };
304
+
305
+ CodeMirror.registerHelper("hint", "auto", function(cm, options) {
306
+ var helpers = cm.getHelpers(cm.getCursor(), "hint");
307
+ if (helpers.length) {
308
+ for (var i = 0; i < helpers.length; i++) {
309
+ var cur = helpers[i](cm, options);
310
+ if (cur && cur.list.length) return cur;
311
+ }
312
+ } else {
313
+ var words = cm.getHelper(cm.getCursor(), "hintWords");
314
+ if (words) return CodeMirror.hint.fromList(cm, {words: words});
315
+ }
316
+ });
317
+
318
+ CodeMirror.registerHelper("hint", "fromList", function(cm, options) {
319
+ var cur = cm.getCursor(), token = cm.getTokenAt(cur);
320
+ var found = [];
321
+ for (var i = 0; i < options.words.length; i++) {
322
+ var word = options.words[i];
323
+ if (word.slice(0, token.string.length) == token.string)
324
+ found.push(word);
325
+ }
326
+
327
+ if (found.length) return {
328
+ list: found,
329
+ from: CodeMirror.Pos(cur.line, token.start),
330
+ to: CodeMirror.Pos(cur.line, token.end)
331
+ };
332
+ });
333
+
334
+ CodeMirror.commands.autocomplete = CodeMirror.showHint;
286
335
  })();