+ autocomplete: curry(function autocomplete(provider, context) {
+ let running = context.getCache("autocomplete-search-running", Object);
+
+ let name = "autocomplete:" + provider;
+ if (!services.has(name))
+ services.add(name, services.AUTOCOMPLETE + provider, "nsIAutoCompleteSearch");
+ let service = services[name];
+
+ util.assert(service, _("autocomplete.noSuchProvider", provider), false);
+
+ if (running[provider]) {
+ this.completions = this.completions;
+ this.cancel();
+ }
+
+ context.anchored = false;
+ context.compare = CompletionContext.Sort.unsorted;
+ context.filterFunc = null;
+
+ let words = context.filter.toLowerCase().split(/\s+/g);
+ context.hasItems = true;
+ context.completions = context.completions.filter(function ({ url, title })
+ words.every(function (w) (url + " " + title).toLowerCase().indexOf(w) >= 0))
+ context.incomplete = true;
+
+ context.format = this.modules.bookmarks.format;
+ context.keys.extra = function (item) {
+ try {
+ return bookmarkcache.get(item.url).extra;
+ }
+ catch (e) {}
+ return null;
+ };
+ context.title = [_("autocomplete.title", provider)];
+
+ context.cancel = function () {
+ this.incomplete = false;
+ if (running[provider])
+ service.stopSearch();
+ running[provider] = false;
+ };
+
+ service.startSearch(context.filter, "", context.result, {
+ onSearchResult: util.wrapCallback(function onSearchResult(search, result) {
+ if (result.searchResult <= result.RESULT_SUCCESS)
+ running[provider] = null;
+
+ context.incomplete = result.searchResult >= result.RESULT_NOMATCH_ONGOING;
+ context.completions = [
+ { url: result.getValueAt(i), title: result.getCommentAt(i), icon: result.getImageAt(i) }
+ for (i in util.range(0, result.matchCount))
+ ];
+ }),
+ get onUpdateSearchResult() this.onSearchResult
+ });
+ running[provider] = true;
+ }),
+