From 87d10fa06bfe63b94ace873df0014128f9769107 Mon Sep 17 00:00:00 2001
From: Marijn Haverbeke <marijn@haverbeke.nl>
Date: Wed, 20 Apr 2016 10:23:44 +0200
Subject: [PATCH] [show-hint addon] Simplify Promise support

Issue #3974
---
 addon/hint/show-hint.js |  35 +++++-------
 demo/complete.html      | 123 +++++++++++++++-------------------------
 doc/manual.html         |   4 +-
 3 files changed, 63 insertions(+), 99 deletions(-)

diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js
index 46ca61b96..f426b5c8c 100644
--- a/addon/hint/show-hint.js
+++ b/addon/hint/show-hint.js
@@ -108,13 +108,11 @@
     },
 
     update: function(first) {
-      if (this.tick == null) return;
-      var self = this;
-      var hint = asynchronifyHinter(this.options.hint)
-      var myTick = ++this.tick;
-      hint(this.cm, function(data) {
-        if (self.tick == myTick) self.finishUpdate(data, first);
-      }, this.options);
+      if (this.tick == null) return
+      var self = this, myTick = ++this.tick
+      fetchHints(this.options.hint, this.cm, this.options, function(data) {
+        if (self.tick == myTick) self.finishUpdate(data, first)
+      })
     },
 
     finishUpdate: function(data, first) {
@@ -360,17 +358,14 @@
     return result
   }
 
-  function asynchronifyHinter(helper){
-    // given a hinter function, return an async one.
-    if(helper.async) return helper
-    var _help = function(cm, callback, option){
-      var res = helper(cm, option)
-      if(res && res.then) return res.then(callback)
-      return callback(res)
+  function fetchHints(hint, cm, options, callback) {
+    if (hint.async) {
+      hint(cm, callback, options)
+    } else {
+      var result = hint(cm, options)
+      if (result && result.then) result.then(callback)
+      else callback(result)
     }
-    _help.async = true;
-    _help.supportsSelection = helper.supportsSelection;
-    return _help;
   }
 
   function resolveAutoHints(cm, pos) {
@@ -380,12 +375,10 @@
         var app = applicableHelpers(cm, helpers);
         function run(i) {
           if (i == app.length) return callback(null)
-          var helper = app[i]
-          helper = asynchronifyHinter(helper);
-          helper(cm, function(result) {
+          fetchHints(app[i], cm, options, function(result) {
             if (result && result.list.length > 0) callback(result)
             else run(i + 1)
-          }, options)
+          })
         }
         run(0)
       }
diff --git a/demo/complete.html b/demo/complete.html
index fac48cbf2..18e17c812 100644
--- a/demo/complete.html
+++ b/demo/complete.html
@@ -70,86 +70,57 @@ on top of the <a href="../doc/manual.html#addon_show-hint"><code>show-hint</code
 and <a href="../doc/manual.html#addon_javascript-hint"><code>javascript-hint</code></a>
 addons.</p>
 
-
-<form><textarea id="synonyms" name="synonyms">
+<form><textarea style="display: none" id="synonyms" name="synonyms">
 Here, the completion use an asynchronous hinting functions to provide
 synonyms for each words. If your browser support `Promises`, the
 hinting function can also return one.
 </textarea></form>
 
+<script>
+var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+  lineNumbers: true,
+  extraKeys: {"Ctrl-Space": "autocomplete"},
+  mode: {name: "javascript", globalVars: true}
+});
+
+if (typeof Promise !== undefined) {
+  var comp = [
+    ["here", "hither"],
+    ["asynchronous", "nonsynchronous"],
+    ["completion", "achievement", "conclusion", "culmination", "expirations"],
+    ["hinting", "advive", "broach", "imply"],
+    ["function","action"],
+    ["provide", "add", "bring", "give"],
+    ["synonyms", "equivalents"],
+    ["words", "token"],
+    ["each", "every"],
+  ]
+
+  function synonyms(cm, option) {
+    return new Promise(function(accept) {
+      setTimeout(function() {
+        var cursor = cm.getCursor(), line = cm.getLine(cursor.line)
+        var start = cursor.ch, end = cursor.ch
+        while (start && /\w/.test(line.charAt(start - 1))) --start
+        while (end < line.length && /\w/.test(line.charAt(end))) ++end
+        var word = line.slice(start, end).toLowerCase()
+        for (var i = 0; i < comp.length; i++) if (comp[i].indexOf(word) != -1)
+          return accept({list: comp[i],
+                         from: CodeMirror.Pos(cursor.line, start),
+                         to: CodeMirror.Pos(cursor.line, end)})
+        return accept(null)
+      }, 100)
+    })
+  }
 
+  var editor2 = CodeMirror.fromTextArea(document.getElementById("synonyms"), {
+    extraKeys: {"Ctrl-Space": "autocomplete"},
+    lineNumbers: true,
+    lineWrapping: true,
+    mode: "text/x-markdown",
+    hintOptions: {hint: synonyms}
+  })
+}
+</script>
 
-     <script>
-        var comp=[
-            ['Here', 'Hither'],
-            ['asynchronous', 'nonsynchronous'],
-            ['completion','achievement','conclusion','culmination','expirations'],
-            ['hinting', 'advive', 'broach', 'imply'],
-            ['function','action'],
-            ['provide', 'add', 'bring', 'give'],
-            ['synonyms', 'equivalents'],
-            ['words','token'],
-            ['each','every'],
-        ]
-        
-        var async_synonyms =  function(editor, callback ,option){
-                var cursor = editor.getCursor();
-                var token = editor.getTokenAt(cursor);
-                var start = {line:cursor.line, ch:token.start};
-                var end = {line:cursor.line, ch:token.end};
-                var res = [];
-                var name = token.string;
-                for(var i in comp){
-                    if(comp[i].indexOf(name) !== -1){
-                        res = comp[i];
-                        break;
-                    }
-                }
-                callback({list:res, from:start, to:end})
-            }
-        async_synonyms.async = true;
-        CodeMirror.registerGlobalHelper('hint', 'synonyms', function(mode){
-            if ( mode && mode.name === 'markdown')
-                return true;
-            return false;
-        }, async_synonyms)
-
-
-        if(typeof Promise !== undefined){
-            CodeMirror.registerGlobalHelper('hint', 'synonyms', function(mode){
-            if ( mode && mode.name === 'markdown')
-                return true;
-            return false;
-            }, function(editor, optio){
-                var cursor = editor.getCursor();
-                var token = editor.getTokenAt(cursor);
-                var start = {line:cursor.line, ch:token.start};
-                var end = {line:cursor.line, ch:token.end};
-                var res = ['No','completions','but','you', 'can','use', 'Promises'];
-                
-                return Promise.resolve({list:res, from:start, to:end})
-
-            })
-
-        }
-     </script>
-
-
-    <script>
-      var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
-        lineNumbers: true,
-        extraKeys: {"Ctrl-Space": "autocomplete"},
-        mode: {name: "javascript", globalVars: true}
-      });
-
-      var editor2 = CodeMirror.fromTextArea(document.getElementById("synonyms"), {
-        extraKeys: {"Ctrl-Space": "autocomplete"},
-        lineNumbers: true,
-        lineWrapping: true,
-        mode: 'text/x-markdown'
-      });
-      editor2.setSize(null, '7em')
-
-    </script>
-
-  </article>
+</article>
diff --git a/doc/manual.html b/doc/manual.html
index 6588e71ce..5f3b2330b 100644
--- a/doc/manual.html
+++ b/doc/manual.html
@@ -2568,9 +2568,9 @@ editor.setOption("extraKeys", {
         <dt><code><strong>to</strong>: {line, ch}</code></dt>
         <dd>Optional <code>to</code> position that will be used by <code>pick()</code> instead
         of the global one passed with the full list of completions.</dd>
-      </dl>
+      </dl></dd>
       
-      <dd> The plugin understands the following options (the options object
+      <dd>The plugin understands the following options (the options object
       will also be passed along to the hinting function, which may
       understand additional options):
       <dl>
-- 
GitLab