1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 * This module exports a provider that offers restrict keywords autofill for
13 } from "resource:///modules/UrlbarUtils.sys.mjs";
17 ChromeUtils.defineESModuleGetters(lazy, {
18 UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
19 UrlbarResult: "resource:///modules/UrlbarResult.sys.mjs",
20 UrlbarTokenizer: "resource:///modules/UrlbarTokenizer.sys.mjs",
23 const RESTRICT_KEYWORDS_FEATURE_GATE = "searchRestrictKeywords.featureGate";
26 * Class used to create the provider.
28 class ProviderRestrictKeywordsAutofill extends UrlbarProvider {
30 #lowerCaseTokenToKeywords;
37 return "RestrictKeywordsAutofill";
41 return UrlbarUtils.PROVIDER_TYPE.HEURISTIC;
48 async #getLowerCaseTokenToKeywords() {
49 let tokenToKeywords = await lazy.UrlbarTokenizer.getL10nRestrictKeywords();
51 this.#lowerCaseTokenToKeywords = new Map(
52 [...tokenToKeywords].map(([token, keywords]) => [
54 keywords.map(keyword => keyword.toLowerCase()),
58 return this.#lowerCaseTokenToKeywords;
61 async #getKeywordAliases() {
62 return Array.from(await this.#lowerCaseTokenToKeywords.values())
64 .map(keyword => "@" + keyword);
67 async isActive(queryContext) {
68 if (!lazy.UrlbarPrefs.getScotchBonnetPref(RESTRICT_KEYWORDS_FEATURE_GATE)) {
72 this.#autofillData = null;
75 queryContext.searchMode ||
76 queryContext.tokens.length != 1 ||
77 queryContext.searchString.length == 1 ||
78 queryContext.restrictSource ||
79 !queryContext.searchString.startsWith("@")
84 // Returns partial autofill result when the user types
85 // @h, @hi, @hist, etc.
86 if (lazy.UrlbarPrefs.get("autoFill") && queryContext.allowAutofill) {
87 let instance = this.queryInstance;
88 let result = await this.#getAutofillResult(queryContext);
89 if (result && instance == this.queryInstance) {
90 this.#autofillData = { result, instance };
95 // Returns full autofill result when user types keyword with space to
96 // enter seach mode. Example, "@history ".
97 let keywordAliases = await this.#getKeywordAliases();
99 keywordAliases.some(keyword =>
100 keyword.startsWith(queryContext.trimmedLowerCaseSearchString)
109 async startQuery(queryContext, addCallback) {
111 this.#autofillData &&
112 this.#autofillData.instance == this.queryInstance
114 addCallback(this, this.#autofillData.result);
118 let instance = this.queryInstance;
119 let typedKeyword = queryContext.lowerCaseSearchString;
120 let typedKeywordTrimmed =
121 queryContext.trimmedLowerCaseSearchString.substring(1);
122 let tokenToKeywords = await this.#getLowerCaseTokenToKeywords();
124 if (instance != this.queryInstance) {
131 for (let [token, keywords] of tokenToKeywords) {
132 if (keywords.includes(typedKeywordTrimmed)) {
133 restrictSymbol = token;
134 aliasKeyword = "@" + typedKeywordTrimmed + " ";
139 if (restrictSymbol && typedKeyword == aliasKeyword) {
140 let result = new lazy.UrlbarResult(
141 UrlbarUtils.RESULT_TYPE.RESTRICT,
142 UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
143 ...lazy.UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
144 keyword: restrictSymbol,
145 providesSearchMode: false,
148 result.heuristic = true;
149 addCallback(this, result);
152 this.#autofillData = null;
156 if (this.#autofillData?.instance == this.queryInstance) {
157 this.#autofillData = null;
161 async #getAutofillResult(queryContext) {
162 let tokenToKeywords = await this.#getLowerCaseTokenToKeywords();
163 let { lowerCaseSearchString } = queryContext;
165 for (let [token, l10nRestrictKeywords] of tokenToKeywords.entries()) {
166 let keywords = [...l10nRestrictKeywords].map(keyword => `@${keyword}`);
167 let autofillKeyword = keywords.find(keyword =>
168 keyword.startsWith(lowerCaseSearchString)
172 if (autofillKeyword) {
173 // Add an autofill result. Append a space so the user can hit enter
174 // or the right arrow key and immediately start typing their query.
175 let keywordPreservingUserCase =
176 queryContext.searchString +
177 autofillKeyword.substr(queryContext.searchString.length);
178 let value = keywordPreservingUserCase + " ";
179 let icon = UrlbarUtils.LOCAL_SEARCH_MODES.find(
180 mode => mode.restrict == token
183 let result = new lazy.UrlbarResult(
184 UrlbarUtils.RESULT_TYPE.RESTRICT,
185 UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
186 ...lazy.UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
189 l10nRestrictKeywords: [
190 l10nRestrictKeywords,
191 UrlbarUtils.HIGHLIGHT.TYPED,
194 keywordPreservingUserCase,
195 UrlbarUtils.HIGHLIGHT.TYPED,
197 providesSearchMode: true,
203 selectionStart: queryContext.searchString.length,
204 selectionEnd: value.length,
215 export var UrlbarProviderRestrictKeywordsAutofill =
216 new ProviderRestrictKeywordsAutofill();