From b2ff98e2f8a3f03edf4d526f8ad27de781e02648 Mon Sep 17 00:00:00 2001 From: Harry Twyford Date: Sat, 11 Jul 2020 22:53:11 +0000 Subject: [PATCH] Bug 1648468 - Part 3 - Allow UrlbarProviderTokenAliasEngines to provide its own heuristic result. r=adw Differential Revision: https://phabricator.services.mozilla.com/D82236 --- .../urlbar/UrlbarMuxerUnifiedComplete.jsm | 1 + .../UrlbarProviderTokenAliasEngines.jsm | 106 +++++++++++++++--- toolkit/components/places/UnifiedComplete.jsm | 67 +---------- 3 files changed, 91 insertions(+), 83 deletions(-) diff --git a/browser/components/urlbar/UrlbarMuxerUnifiedComplete.jsm b/browser/components/urlbar/UrlbarMuxerUnifiedComplete.jsm index 871fa10ca03d..93c0e4f06311 100644 --- a/browser/components/urlbar/UrlbarMuxerUnifiedComplete.jsm +++ b/browser/components/urlbar/UrlbarMuxerUnifiedComplete.jsm @@ -49,6 +49,7 @@ const heuristicOrder = [ "Omnibox", "UnifiedComplete", "Autofill", + "TokenAliasEngines", "HeuristicFallback", ]; /** diff --git a/browser/components/urlbar/UrlbarProviderTokenAliasEngines.jsm b/browser/components/urlbar/UrlbarProviderTokenAliasEngines.jsm index d654b08a061c..24ccfb0fb93d 100644 --- a/browser/components/urlbar/UrlbarProviderTokenAliasEngines.jsm +++ b/browser/components/urlbar/UrlbarProviderTokenAliasEngines.jsm @@ -14,6 +14,7 @@ const { XPCOMUtils } = ChromeUtils.import( "resource://gre/modules/XPCOMUtils.jsm" ); XPCOMUtils.defineLazyModuleGetters(this, { + UrlbarPrefs: "resource:///modules/UrlbarPrefs.jsm", UrlbarProvider: "resource:///modules/UrlbarUtils.jsm", UrlbarResult: "resource:///modules/UrlbarResult.jsm", UrlbarSearchUtils: "resource:///modules/UrlbarSearchUtils.jsm", @@ -44,7 +45,7 @@ class ProviderTokenAliasEngines extends UrlbarProvider { * @returns {integer} one of the types from UrlbarUtils.PROVIDER_TYPE.* */ get type() { - return UrlbarUtils.PROVIDER_TYPE.PROFILE; + return UrlbarUtils.PROVIDER_TYPE.HEURISTIC; } get PRIORITY() { @@ -60,12 +61,34 @@ class ProviderTokenAliasEngines extends UrlbarProvider { * @returns {boolean} Whether this provider should be invoked for the search. */ async isActive(queryContext) { - this._engines = []; - if (queryContext.searchString.trim() == "@") { - this._engines = await UrlbarSearchUtils.tokenAliasEngines(); + // Once the user starts typing a search string after the token, we hand off + // suggestions to UrlbarProviderSearchSuggestions. + if ( + !queryContext.searchString.startsWith("@") || + queryContext.tokens.length != 1 + ) { + return false; } - return this._engines.length; + this._engines = await UrlbarSearchUtils.tokenAliasEngines(); + if (!this._engines.length) { + return false; + } + + if (queryContext.searchString.trim() == "@") { + return true; + } + + // If there's no engine associated with the searchString, then we don't want + // to block other kinds of results. + if (UrlbarPrefs.get("autoFill") && queryContext.allowAutofill) { + this._autofillResult = this._getAutofillResult(queryContext); + if (this._autofillResult) { + return true; + } + } + + return false; } /** @@ -89,19 +112,25 @@ class ProviderTokenAliasEngines extends UrlbarProvider { return; } - for (let { engine, tokenAliases } of this._engines) { - let result = new UrlbarResult( - UrlbarUtils.RESULT_TYPE.SEARCH, - UrlbarUtils.RESULT_SOURCE.SEARCH, - ...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, { - engine: [engine.name, UrlbarUtils.HIGHLIGHT.TYPED], - keyword: [tokenAliases[0], UrlbarUtils.HIGHLIGHT.TYPED], - query: ["", UrlbarUtils.HIGHLIGHT.TYPED], - icon: engine.iconURI ? engine.iconURI.spec : null, - keywordOffer: UrlbarUtils.KEYWORD_OFFER.SHOW, - }) - ); - addCallback(this, result); + if (queryContext.searchString.trim() == "@") { + for (let { engine, tokenAliases } of this._engines) { + let result = new UrlbarResult( + UrlbarUtils.RESULT_TYPE.SEARCH, + UrlbarUtils.RESULT_SOURCE.SEARCH, + ...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, { + engine: [engine.name, UrlbarUtils.HIGHLIGHT.TYPED], + keyword: [tokenAliases[0], UrlbarUtils.HIGHLIGHT.TYPED], + query: ["", UrlbarUtils.HIGHLIGHT.TYPED], + icon: engine.iconURI ? engine.iconURI.spec : "", + keywordOffer: UrlbarUtils.KEYWORD_OFFER.SHOW, + }) + ); + addCallback(this, result); + } + } else if (this._autofillResult) { + addCallback(this, this._autofillResult); + this.queries.delete(queryContext); + return; } this.queries.delete(queryContext); @@ -121,8 +150,49 @@ class ProviderTokenAliasEngines extends UrlbarProvider { * @param {object} queryContext The query context object */ cancelQuery(queryContext) { + delete this._autofillResult; this.queries.delete(queryContext); } + + _getAutofillResult(queryContext) { + let token = queryContext.tokens[0]; + // The user is typing a specific engine. We should show a heuristic result. + for (let { engine, tokenAliases } of this._engines) { + for (let alias of tokenAliases) { + if (alias.startsWith(token.lowerCaseValue)) { + // We found a specific engine. We will add an autofill result. + let aliasPreservingUserCase = + token.value + alias.substr(token.value.length); + let value = aliasPreservingUserCase + " "; + let result = new UrlbarResult( + UrlbarUtils.RESULT_TYPE.SEARCH, + UrlbarUtils.RESULT_SOURCE.SEARCH, + ...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, { + engine: [engine.name, UrlbarUtils.HIGHLIGHT.TYPED], + keyword: [aliasPreservingUserCase, UrlbarUtils.HIGHLIGHT.TYPED], + query: ["", UrlbarUtils.HIGHLIGHT.TYPED], + icon: engine.iconURI ? engine.iconURI.spec : "", + keywordOffer: UrlbarUtils.KEYWORD_OFFER.HIDE, + // For test interoperabilty with UrlbarProviderSearchSuggestions. + suggestion: undefined, + tailPrefix: undefined, + tail: undefined, + tailOffsetIndex: -1, + isSearchHistory: false, + }) + ); + result.heuristic = true; + result.autofill = { + value, + selectionStart: queryContext.searchString.length, + selectionEnd: value.length, + }; + return result; + } + } + } + return null; + } } var UrlbarProviderTokenAliasEngines = new ProviderTokenAliasEngines(); diff --git a/toolkit/components/places/UnifiedComplete.jsm b/toolkit/components/places/UnifiedComplete.jsm index 6f4153fa012a..02f55606105a 100644 --- a/toolkit/components/places/UnifiedComplete.jsm +++ b/toolkit/components/places/UnifiedComplete.jsm @@ -814,16 +814,14 @@ Search.prototype = { // If the heuristic result is an engine from a token alias, the search // restriction char, or we're in search-restriction mode, then we're done. // UrlbarProviderSearchSuggestions will handle suggestions, if any. - let tokenAliasQuery = - this._searchEngineAliasMatch && - this._searchEngineAliasMatch.isTokenAlias; let emptySearchRestriction = this._trimmedOriginalSearchString.length <= 3 && this._leadingRestrictionToken == UrlbarTokenizer.RESTRICT.SEARCH && /\s*\S?$/.test(this._trimmedOriginalSearchString); if ( emptySearchRestriction || - tokenAliasQuery || + (tokenAliasEngines && + this._trimmedOriginalSearchString.startsWith("@")) || (this.hasBehavior("search") && this.hasBehavior("restrict")) ) { this._autocompleteSearch.finishSearch(true); @@ -1000,60 +998,6 @@ Search.prototype = { return true; }, - async _matchSearchEngineTokenAliasForAutofill() { - // We need an "@engine" heuristic token. - let token = this._heuristicToken; - if (!token || token.length == 1 || !token.startsWith("@")) { - return false; - } - - // See if any engine has a token alias that starts with the heuristic token. - let engines = await UrlbarSearchUtils.tokenAliasEngines(); - for (let { engine, tokenAliases } of engines) { - for (let alias of tokenAliases) { - if (alias.startsWith(token.toLocaleLowerCase())) { - // We found one. The match we add here is a little special compared - // to others. It needs to be an autofill match and its `value` must - // be the string that will be autofilled so that the controller will - // autofill it. But it also must be a searchengine action so that the - // front end will style it as a search engine result. The front end - // uses `finalCompleteValue` as the URL for autofill results, so set - // that to the moz-action URL. - let aliasPreservingUserCase = token + alias.substr(token.length); - let value = aliasPreservingUserCase + " "; - this._result.setDefaultIndex(0); - this._addMatch({ - value, - finalCompleteValue: makeActionUrl("searchengine", { - engineName: engine.name, - alias: aliasPreservingUserCase, - input: value, - searchQuery: "", - }), - comment: engine.name, - frecency: FRECENCY_DEFAULT, - style: "autofill action searchengine", - icon: engine.iconURI ? engine.iconURI.spec : null, - }); - - // Set _searchEngineAliasMatch with an empty query so that we don't - // attempt to add any more matches. When a token alias is autofilled, - // the only match should be the one we just added. - this._searchEngineAliasMatch = { - engine, - alias: aliasPreservingUserCase, - query: "", - isTokenAlias: true, - }; - - return true; - } - } - } - - return false; - }, - async _matchFirstHeuristicResult(conn) { // We always try to make the first result a special "heuristic" result. The // heuristics below determine what type of result it will be, if any. @@ -1083,13 +1027,6 @@ Search.prototype = { } } - if (this.pending && shouldAutofill) { - let matched = await this._matchSearchEngineTokenAliasForAutofill(); - if (matched) { - return true; - } - } - // Fall back to UrlbarProviderHeuristicFallback. return false; },