code: function updateArgHints(ts, cm) {
      closeArgHints(ts);
  
      if (cm.somethingSelected()) return;
      var state = cm.getTokenAt(cm.getCursor()).state;
      var inner = CodeMirror.innerMode(cm.getMode(), state);
      if (inner.mode.name != "javascript") return;
      var lex = inner.state.lexical;
      if (lex.info != "call") return;
  
      var ch, argPos = lex.pos || 0, tabSize = cm.getOption("tabSize");
      for (var line = cm.getCursor().line, e = Math.max(0, line - 9), found = false; line >= e; --line) {
        var str = cm.getLine(line), extra = 0;
        for (var pos = 0;;) {
          var tab = str.indexOf("\t", pos);
          if (tab == -1) break;
          extra += tabSize - (tab + extra) % tabSize - 1;
          pos = tab + 1;
        }
        ch = lex.column - extra;
        if (str.charAt(ch) == "(") {found = true; break;}
      }
      if (!found) return;
  
      var start = Pos(line, ch);
      var cache = ts.cachedArgHints;
      if (cache && cache.doc == cm.getDoc() && cmpPos(start, cache.start) == 0)
        return showArgHints(ts, cm, argPos);
  
      ts.request(cm, {type: "type", preferFunction: true, end: start}, function(error, data) {
        if (error || !data.type || !(/^fn\(/).test(data.type)) return;
        ts.cachedArgHints = {
          start: pos,
          type: parseFnType(data.type),
          name: data.exprName || data.name || "fn",
          guess: data.guess,
          doc: cm.getDoc()
        };
        showArgHints(ts, cm, argPos);
      });
    }
docs: Maintaining argument hints