codemirror-rails 3.20 → 3.21

Sign up to get free protection for your applications and to get access to all the features.
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
  })();