Skip to content

Commit a0729d2

Browse files
committed
Merge branch 'master' of github.com:philc/vimium into feature/vomnibar-results-favicon-size-setting
2 parents 13bc751 + 654edf2 commit a0729d2

14 files changed

+320
-186
lines changed

background_scripts/completion.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -273,10 +273,10 @@ class BookmarkCompleter {
273273
if (queryTerms.length > 0) {
274274
results = this.bookmarks.filter((bookmark) => {
275275
const suggestionTitle = usePathAndTitle ? bookmark.pathAndTitle : bookmark.title;
276-
if (bookmark.hasJavascriptPrefix == null) {
277-
bookmark.hasJavascriptPrefix = Utils.hasJavascriptPrefix(bookmark.url);
276+
if (bookmark.hasJavascriptProtocol == null) {
277+
bookmark.hasJavascriptProtocol = UrlUtils.hasJavascriptProtocol(bookmark.url);
278278
}
279-
if (bookmark.hasJavascriptPrefix && bookmark.shortUrl == null) {
279+
if (bookmark.hasJavascriptProtocol && bookmark.shortUrl == null) {
280280
bookmark.shortUrl = "javascript:...";
281281
}
282282
const suggestionUrl = bookmark.shortUrl != null ? bookmark.shortUrl : bookmark.url;
@@ -477,7 +477,7 @@ class DomainCompleter {
477477

478478
// Return something like "http://www.example.com" or false.
479479
parseDomainAndScheme(url) {
480-
return UrlUtils.hasFullUrlPrefix(url) && !UrlUtils.hasChromePrefix(url) &&
480+
return UrlUtils.urlHasProtocol(url) && !UrlUtils.hasChromeProtocol(url) &&
481481
url.split("/", 3).join("/");
482482
}
483483
}

background_scripts/completion_engines.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class BaseEngine {
4040
return Utils.matchesAnyRegexp(this.regexps, searchUrl);
4141
}
4242
getUrl(queryTerms) {
43-
return UrlUtils.createSearchUrl(queryTerms, this.engineUrl);
43+
return UrlUtils.createSearchUrl(queryTerms.join(" "), this.engineUrl);
4444
}
4545
}
4646

background_scripts/completion_search.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ const CompletionSearch = {
9999

100100
// We don't complete regular URLs or Javascript URLs.
101101
if (queryTerms.length == 1 && await UrlUtils.isUrl(query)) return [];
102-
if (UrlUtils.hasJavascriptPrefix(query)) return [];
102+
if (UrlUtils.hasJavascriptProtocol(query)) return [];
103103

104104
const engine = this.lookupEngine(searchUrl);
105105
if (!engine) return [];

background_scripts/tab_operations.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ async function openUrlInCurrentTab(request) {
1111
// Note that when injecting JavaScript, it's subject to the site's CSP. Sites with strict CSPs
1212
// (like github.com, developer.mozilla.org) will raise an error when we try to run this code. See
1313
// https://github.com/philc/vimium/issues/4331.
14-
if (UrlUtils.hasJavascriptPrefix(request.url)) {
14+
if (UrlUtils.hasJavascriptProtocol(request.url)) {
1515
const scriptingArgs = {
1616
target: { tabId: request.tabId },
1717
func: (text) => {

lib/chrome_api_stubs.js

+3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ if (shouldInstallStubs) {
3737
addListener() {},
3838
},
3939
sendMessage(message) {
40+
// TODO(philc): This stub should return a an empty Promise, not the length of the
41+
// chromeMessages array. Some portion fo the dom_tests.html setup depends on this value, so
42+
// the tests break. Fix.
4043
return chromeMessages.unshift(message);
4144
},
4245
getManifest() {

lib/url_utils.js

+16-30
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ const UrlUtils = {
4040
if (str.includes(" ")) return false;
4141

4242
// Starts with a scheme: URL
43-
if (this.hasFullUrlPrefix(str)) return true;
43+
if (this.urlHasProtocol(str)) return true;
4444

4545
// More or less RFC compliant URL host part parsing. This should be sufficient for our needs
4646
const urlRegex = new RegExp(
@@ -91,40 +91,31 @@ const UrlUtils = {
9191
string = string.trim();
9292

9393
// Special-case about:[url], view-source:[url] and the like
94-
if (this.hasChromePrefix(string)) {
94+
if (this.hasChromeProtocol(string)) {
9595
return string;
96-
} else if (this.hasJavascriptPrefix(string)) {
96+
} else if (this.hasJavascriptProtocol(string)) {
9797
return string;
9898
} else if (await this.isUrl(string)) {
99-
return this.createFullUrl(string);
99+
return this.urlHasProtocol(string) ? string : `http://${string}`;
100100
} else {
101101
const message = `convertToUrl: can't convert "${string}" into a URL. This shouldn't happen.`;
102102
console.error(message);
103103
return null;
104104
}
105105
},
106106

107-
hasChromePrefix: (function () {
108-
const chromePrefixes = ["about:", "view-source:", "extension:", "chrome-extension:", "data:"];
109-
return (url) => chromePrefixes.some((prefix) => url.startsWith(prefix));
110-
})(),
107+
_chromePrefixes: ["about:", "view-source:", "extension:", "chrome-extension:", "data:"],
108+
hasChromeProtocol(url) {
109+
return this._chromePrefixes.some((prefix) => url.startsWith(prefix));
110+
},
111111

112-
hasJavascriptPrefix(url) {
112+
hasJavascriptProtocol(url) {
113113
return url.startsWith("javascript:");
114114
},
115115

116-
hasFullUrlPrefix: (function () {
117-
const urlPrefix = new RegExp("^[a-z][-+.a-z0-9]{2,}://.");
118-
return (url) => urlPrefix.test(url);
119-
})(),
120-
121-
// Completes a partial URL (without scheme)
122-
createFullUrl(partialUrl) {
123-
if (this.hasFullUrlPrefix(partialUrl)) {
124-
return partialUrl;
125-
} else {
126-
return ("http://" + partialUrl);
127-
}
116+
_urlPrefix: new RegExp("^[a-z][-+.a-z0-9]{2,}://."),
117+
urlHasProtocol(url) {
118+
return this._urlPrefix.test(url);
128119
},
129120

130121
// Create a search URL from the given :query using the provided search URL.
@@ -133,16 +124,11 @@ const UrlUtils = {
133124
searchUrl += "%s";
134125
}
135126
searchUrl = searchUrl.replace(/%S/g, query);
136-
return searchUrl.replace(/%s/g, this.createSearchQuery(query));
137-
},
138127

139-
// Map a search query to its URL encoded form. The query may be either a string or an array of
140-
// strings. E.g. "BBC Sport" -> "BBC%20Sport".
141-
createSearchQuery(query) {
142-
if (typeof query === "string") {
143-
query = query.split(/\s+/);
144-
}
145-
return query.map(encodeURIComponent).join("%20");
128+
// Map a search query to its URL encoded form. E.g. "BBC Sport" -> "BBC%20Sport".
129+
const parts = query.split(/\s+/);
130+
const encodedQuery = parts.map(encodeURIComponent).join("%20");
131+
return searchUrl.replace(/%s/g, encodedQuery);
146132
},
147133
};
148134

lib/utils.js

+1-6
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,6 @@ const Utils = {
7878
return () => id += 1;
7979
})(),
8080

81-
// TODO(philc): Move to UrlUrls?
82-
hasJavascriptPrefix(url) {
83-
return url.startsWith("javascript:");
84-
},
85-
8681
// Decode valid escape sequences in a URI. This is intended to mimic the best-effort decoding
8782
// Chrome itself seems to apply when a Javascript URI is enetered into the omnibox (or clicked).
8883
// See https://code.google.com/p/chromium/issues/detail?id=483000, #1611 and #1636.
@@ -419,7 +414,7 @@ const UserSearchEngines = {
419414
const keyword = tokens[0].split(":")[0];
420415
const url = tokens[1];
421416
const description = tokens.length > 2 ? tokens.slice(2).join(" ") : `search (${keyword})`;
422-
if (UrlUtils.hasFullUrlPrefix(url) || UrlUtils.hasJavascriptPrefix(url)) {
417+
if (UrlUtils.urlHasProtocol(url) || UrlUtils.hasJavascriptProtocol(url)) {
423418
results[keyword] = new UserSearchEngine({ keyword, url, description });
424419
}
425420
}

make.js

+74-40
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,12 @@ function createFirefoxManifest(manifest) {
6565
// Firefox supports SVG icons.
6666
Object.assign(manifest, {
6767
"icons": {
68-
"16": "icons/icon.svg",
69-
"32": "icons/icon.svg",
70-
"48": "icons/icon.svg",
71-
"64": "icons/icon.svg",
72-
"96": "icons/icon.svg",
73-
"128": "icons/icon.svg"
68+
"16": "icons/icon.svg",
69+
"32": "icons/icon.svg",
70+
"48": "icons/icon.svg",
71+
"64": "icons/icon.svg",
72+
"96": "icons/icon.svg",
73+
"128": "icons/icon.svg",
7474
},
7575
});
7676

@@ -130,7 +130,10 @@ async function buildStorePackage() {
130130
const firefoxManifest = createFirefoxManifest(chromeManifest);
131131
await writeDistManifest(firefoxManifest);
132132
// Exclude PNG icons from the Firefox build, because we use the SVG directly.
133-
await shell("bash", ["-c", `${zipCommand} ../firefox/vimium-firefox-${version}.zip . -x icons/*.png`]);
133+
await shell("bash", [
134+
"-c",
135+
`${zipCommand} ../firefox/vimium-firefox-${version}.zip . -x icons/*.png`,
136+
]);
134137

135138
// Build the Chrome Store package.
136139
await writeDistManifest(chromeManifest);
@@ -163,49 +166,55 @@ const runUnitTests = async () => {
163166
return await shoulda.run();
164167
};
165168

166-
const runDomTests = async (port) => {
167-
const testUrl = `http://localhost:${port}/tests/dom_tests/dom_tests.html`;
168-
169-
const browser = await puppeteer.launch();
170-
const page = await browser.newPage();
171-
let receivedErrorOutput = false;
172-
169+
function setupPuppeteerPageForTests(page) {
170+
// The "console" event emitted has arguments which are promises. To obtain the values to be
171+
// printed, we must resolve those promises. However, if many console messages are emitted at once,
172+
// resolving the promises often causes the console.log messages to be printed out of order. Here,
173+
// we use a queue to strictly enforce that the messages appear in the order in which they were
174+
// logged.
175+
const messageQueue = [];
176+
let processing = false;
177+
const processMessageQueue = async () => {
178+
while (messageQueue.length > 0) {
179+
const values = await Promise.all(messageQueue.shift());
180+
console.log(...values);
181+
}
182+
processing = false;
183+
};
173184
page.on("console", async (msg) => {
174-
const args = await Promise.all(msg.args().map((a) => a.jsonValue()));
175-
console.log(...args);
185+
const values = msg.args().map((a) => a.jsonValue());
186+
messageQueue.push(values);
187+
if (!processing) {
188+
processing = true;
189+
processMessageQueue();
190+
}
176191
});
192+
177193
page.on("error", (err) => {
178-
// As far as I can tell, this handler never gets executed.
194+
// NOTE(philc): As far as I can tell, this handler never gets executed.
179195
console.error(err);
180196
});
181197
// pageerror catches the same events that window.onerror would, like JavaScript parsing errors.
182198
page.on("pageerror", (error) => {
183-
receivedErrorOutput = true;
199+
// This is an arbitrary field we're writing to the page object.
200+
page.receivedErrorOutput = true;
184201
// Whatever type error is, it requires toString() to print the message.
185202
console.log(error.toString());
186203
});
187-
page.on(
188-
"requestfailed",
189-
(request) => console.log(console.log(`${request.failure().errorText} ${request.url()}`)),
190-
);
191-
192-
page.goto(testUrl);
204+
page.on("requestfailed", (request) => {
205+
console.log(`${request.failure().errorText} ${request.url()}`);
206+
});
207+
}
193208

209+
// Navigates the Puppeteer `page` to `url` and invokes shoulda.run().
210+
async function runPuppeteerTest(page, url) {
211+
page.goto(url);
194212
await page.waitForNavigation({ waitUntil: "load" });
195-
196213
const success = await page.evaluate(async () => {
197214
return await shoulda.run();
198215
});
199-
200-
// NOTE(philc): At one point in development, I noticed that the output from Deno would suddenly
201-
// pause, prior to the tests fully finishing, so closing the browser here may be racy. If it
202-
// occurs again, we may need to add "await delay(200)".
203-
await browser.close();
204-
if (receivedErrorOutput) {
205-
throw new Error("The tests fail because there was a page-level error.");
206-
}
207216
return success;
208-
};
217+
}
209218

210219
desc("Download and parse list of top-level domains (TLDs)");
211220
task("fetch-tlds", [], async () => {
@@ -228,8 +237,7 @@ task("test-unit", [], async () => {
228237
}
229238
});
230239

231-
desc("Run DOM tests");
232-
task("test-dom", [], async () => {
240+
async function testDom() {
233241
const port = await getAvailablePort();
234242
let served404 = false;
235243
const httpServer = Deno.serve({ port }, async (req) => {
@@ -247,15 +255,41 @@ task("test-dom", [], async () => {
247255
}
248256
});
249257

250-
const success = await runDomTests(port);
251-
if (served404) {
252-
console.log("Tests failed because a background or content script requested a missing file.");
258+
const files = ["dom_tests.html", "vomnibar_test.html"];
259+
const browser = await puppeteer.launch();
260+
let success = true;
261+
for (const file of files) {
262+
const page = await browser.newPage();
263+
console.log("Running", file);
264+
setupPuppeteerPageForTests(page);
265+
const url = `http://localhost:${port}/tests/dom_tests/${file}?dom_tests=true`;
266+
const result = await runPuppeteerTest(page, url);
267+
success = success && result;
268+
if (served404) {
269+
console.log(`${file} failed: a background or content script requested a missing file.`);
270+
}
271+
if (page.receivedErrorOutput) {
272+
console.log(`${file} failed: there was a page level error.`);
273+
success = false;
274+
}
275+
// If we close the puppeteer page (tab) via page.close(), we can get innocuous but noisy output
276+
// like this:
277+
// net::ERR_ABORTED http://localhost:43524/pages/hud.html?dom_tests=true
278+
// There's probably a way to prevent that, but as a work around, we avoid closing the page.
279+
// browser.close() will close all of its owned pages.
253280
}
281+
// NOTE(philc): At one point in development, I noticed that the output from Deno would suddenly
282+
// pause, prior to the tests fully finishing, so closing the browser here may be racy. If it
283+
// occurs again, we may need to add "await delay(200)".
284+
await browser.close();
254285
await httpServer.shutdown();
255286
if (served404 || !success) {
256287
abort("test-dom failed.");
257288
}
258-
});
289+
}
290+
291+
desc("Run DOM tests");
292+
task("test-dom", [], testDom);
259293

260294
desc("Run unit and DOM tests");
261295
task("test", ["test-unit", "test-dom"]);

pages/vomnibar.html

+1-8
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,7 @@
33
<head>
44
<title>Vomnibar</title>
55
<meta name="color-scheme" content="light dark">
6-
<script src="../lib/utils.js"></script>
7-
<script src="../lib/url_utils.js"></script>
8-
<script src="../lib/settings.js"></script>
9-
<script src="../lib/keyboard_utils.js"></script>
10-
<script src="../lib/dom_utils.js"></script>
11-
<script src="../lib/handler_stack.js"></script>
12-
<script src="ui_component_server.js"></script>
13-
<script src="vomnibar.js"></script>
6+
<script type="module" src="vomnibar.js"></script>
147
<link rel="stylesheet" type="text/css" href="../content_scripts/vimium.css" />
158
<link rel="stylesheet" type="text/css" href="vomnibar.css" />
169
</head>

0 commit comments

Comments
 (0)