Skip to content

Commit 278829e

Browse files
authored
Merge branch 'master' into feat/move-tab-to-existing-window
2 parents 073f1e4 + a023a65 commit 278829e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+2558
-1847
lines changed

.github/ISSUE_TEMPLATE/bug_report.md

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ about: File a bug
44
title: ''
55
labels: ''
66
assignees: ''
7-
87
---
98

109
**Describe the bug**

CHANGELOG.md

+17-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
2.1.3 (unreleased)
2+
3+
- Add findSelected and findSelectedBackwards commands.
4+
([#4502](https://github.com/philc/vimium/pull/4502))
5+
- Add commands zoomIn, zoomOut, zoomReset (zi, zo, z0), and setZoom.
6+
([#4488](https://github.com/philc/vimium/pull/4488))
7+
- Add "reload hard" command (bound to R). ([#4445](https://github.com/philc/vimium/pull/4445)).
8+
- Options page: improve UX, add error validation.
9+
- Make tab commands handle Firefox hidden tabs.
10+
- Bug fixes.
11+
112
2.1.2 (2024-04-03)
213

314
- Better fix for Vomnibar doesn't always list tabs by recency.
@@ -46,7 +57,8 @@
4657

4758
2.0.1 (2023-10-04)
4859

49-
- Fix exception when migrating some pre-v2.0 settings. ([#4323](https://github.com/philc/vimium/issues/4323))
60+
- Fix exception when migrating some pre-v2.0 settings.
61+
([#4323](https://github.com/philc/vimium/issues/4323))
5062

5163
2.0.0 (2023-09-28 -- partially rolled out to users on the Chrome store)
5264

@@ -62,14 +74,15 @@
6274
- Allow find mode to work when using only private windows.
6375
([#3614](https://github.com/philc/vimium/issues/3614))
6476
- Add a count option to closeTabsOnLeft and closeTabsOnRight commands, to allow binding a key to
65-
"close just 1 tab on the left/right" rather than closing all tabs, as is the default. E.g. `map cl
77+
"close just 1 tab on the left/right" rather than closing all tabs, as is the default. E.g.
78+
`map cl
6679
closeTabsOnLeft count=1`. ([#4296](https://github.com/philc/vimium/pull/4296))
6780
- Add search completions for Brave Search. ([#3851](https://github.com/philc/vimium/pull/3851))
6881
- Make regular expressions in find mode work again; other find mode improvements.
6982
([#4261](https://github.com/philc/vimium/issues/4261))
7083
- Bug fixes. ([#3944](https://github.com/philc/vimium/pull/3944),
71-
[#3752](https://github.com/philc/vimium/pull/3752),
72-
[#3675](https://github.com/philc/vimium/pull/3675))
84+
[#3752](https://github.com/philc/vimium/pull/3752),
85+
[#3675](https://github.com/philc/vimium/pull/3675))
7386

7487
1.67.7 (2023-07-12)
7588

CONTRIBUTING.md

+3-4
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ Here's the rationale behind this policy:
7575
- Adding a new feature is only part of the work. Once it's added, a feature must be maintained
7676
forever.
7777
- Vimium is a project which suffers from the
78-
[stadium model of open source](https://645ventures.com/voices/articles/github-at-scale-and-how-to-help-stadium-model-maintainers):
78+
[stadium model of open source](https://github.com/philc/book-notes/blob/master/engineering/working%20in%20public%20-%20nadia%20eghbal.md#the-structure-of-an-open-source-project-chap-2):
7979
there are many users but unfortunately few maintainers. As a result, there is bandwidth to
8080
maintain only a limited number of features in the main repo.
8181

@@ -110,9 +110,8 @@ Our tests use [shoulda.js](https://github.com/philc/shoulda.js) and
110110
[Puppeteer](https://github.com/puppeteer/puppeteer). To run the tests:
111111

112112
1. Install [Deno](https://deno.land/) if you don't have it already.
113-
1. `PUPPETEER_PRODUCT=chrome deno run -A --unstable https://deno.land/x/[email protected]/install.ts`
114-
to install [Puppeteer](https://github.com/lucacasonato/deno-puppeteer)
115-
1. `./make.js test` to build the code and run the tests.
113+
2. `deno run -A npm:puppeteer browsers install chrome` to install puppeteer
114+
3. `./make.js test` to build the code and run the tests.
116115

117116
### Coding Style
118117

README.md

+5-3
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ spirit of the Vim editor.
55

66
**Installation instructions:**
77

8-
* Chrome: [Chrome web store](https://chrome.google.com/extensions/detail/dbepggeogbaibhgnhhndojpepiihcmeb)
9-
* Edge: [Edge Add-ons](https://microsoftedge.microsoft.com/addons/detail/vimium/djmieaghokpkpjfbpelnlkfgfjapaopa)
10-
* Firefox: [Firefox Add-ons](https://addons.mozilla.org/en-GB/firefox/addon/vimium-ff/)
8+
- Chrome:
9+
[Chrome web store](https://chrome.google.com/extensions/detail/dbepggeogbaibhgnhhndojpepiihcmeb)
10+
- Edge:
11+
[Edge Add-ons](https://microsoftedge.microsoft.com/addons/detail/vimium/djmieaghokpkpjfbpelnlkfgfjapaopa)
12+
- Firefox: [Firefox Add-ons](https://addons.mozilla.org/en-GB/firefox/addon/vimium-ff/)
1113

1214
To install from source, see [here](CONTRIBUTING.md#installing-from-source).
1315

background_scripts/commands.js

+61-32
Original file line numberDiff line numberDiff line change
@@ -51,26 +51,23 @@ const Commands = {
5151

5252
// Parses the text supplied by the user in their "keyMappings" setting.
5353
// - shouldLogWarnings: if true, logs to the console when part of the user's config is invalid.
54-
// Returns { keyToRegistryEntry, keyToMappedKey }.
54+
// Returns { keyToRegistryEntry, keyToMappedKey, validationErrors }.
5555
parseKeyMappingsConfig(configText, shouldLogWarnings) {
5656
let keyToRegistryEntry = {};
5757
let mapKeyRegistry = {};
58+
const errors = [];
5859

5960
const configLines = Utils.parseLines(configText);
60-
const logWarning = (...args) => {
61-
if (!shouldLogWarnings) return;
62-
console.warn.apply(console, args);
63-
};
6461

6562
for (const line of configLines) {
6663
const tokens = line.split(/\s+/);
67-
const command = tokens[0].toLowerCase();
68-
switch (command) {
64+
const action = tokens[0].toLowerCase();
65+
switch (action) {
6966
case "map":
7067
if (tokens.length >= 3) {
7168
const [_, key, command, ...optionList] = tokens;
7269
if (!this.availableCommands[command]) {
73-
logWarning(`"${command}" is not a valid command in the line:`, line);
70+
errors.push(`"${command}" is not a valid command in the line: ${line}`);
7471
continue;
7572
}
7673
const keySequence = this.parseKeySequence(key);
@@ -87,7 +84,7 @@ const Commands = {
8784
break;
8885
case "unmap":
8986
if (tokens.length != 2) {
90-
logWarning("Incorrect usage for unmap in the line:", line);
87+
errors.push(`Incorrect usage for unmap in the line: ${line}`);
9188
continue;
9289
}
9390
const key = tokens[1];
@@ -100,7 +97,7 @@ const Commands = {
10097
break;
10198
case "mapkey":
10299
if (tokens.length != 3) {
103-
logWarning("Incorrect usage for mapkey in the line:", line);
100+
errors.push(`Incorrect usage for mapKey in the line: ${line}`);
104101
continue;
105102
}
106103
const fromChar = this.parseKeySequence(tokens[1]);
@@ -111,20 +108,20 @@ const Commands = {
111108
if (isValid) {
112109
mapKeyRegistry[fromChar[0]] = toChar[0];
113110
} else {
114-
logWarning(
115-
"mapkey only supports mapping keys which are single characters. Line:",
116-
line,
111+
errors.push(
112+
`mapkey only supports mapping keys which are single characters. Line: ${line}`,
117113
);
118114
}
119115
break;
120116
default:
121-
logWarning(`"${command}" is not a valid config command in line:`, line);
117+
errors.push(`"${action}" is not a valid config command in line: ${line}`);
122118
}
123119
}
124120

125121
return {
126122
keyToRegistryEntry,
127123
keyToMappedKey: mapKeyRegistry,
124+
validationErrors: errors,
128125
};
129126
},
130127

@@ -257,24 +254,46 @@ const Commands = {
257254
// Build the "helpPageData" data structure which the help page needs and place it in Chrome
258255
// storage.
259256
prepareHelpPageData() {
260-
const commandToKey = {};
257+
/*
258+
Map of commands to option sets to keys to trigger that command option set.
259+
Commands with no options will have the empty string options set.
260+
Example:
261+
{
262+
"zoomReset": {
263+
"": ["z0", "zz"] // No options, with two key maps, ie: `map zz zoomReset`
264+
},
265+
"setZoom": {
266+
"1.1": ["z1"], // `map z1 setZoom 1.1`
267+
"1.2": ["z2"], // `map z2 setZoom 1.2`
268+
}
269+
}
270+
*/
271+
const commandToOptionsToKeys = {};
261272
for (const key of Object.keys(this.keyToRegistryEntry || {})) {
262273
const registryEntry = this.keyToRegistryEntry[key];
263-
(commandToKey[registryEntry.command] != null
264-
? commandToKey[registryEntry.command]
265-
: (commandToKey[registryEntry.command] = [])).push(key);
274+
const optionString = registryEntry.optionList?.join(" ") || "";
275+
commandToOptionsToKeys[registryEntry.command] ||= {};
276+
commandToOptionsToKeys[registryEntry.command][optionString] ||= [];
277+
commandToOptionsToKeys[registryEntry.command][optionString].push(key);
266278
}
267279
const commandGroups = {};
268280
for (const group of Object.keys(this.commandGroups || {})) {
269281
const commands = this.commandGroups[group];
270282
commandGroups[group] = [];
271283
for (const command of commands) {
272-
commandGroups[group].push({
273-
command,
274-
description: this.availableCommands[command].description,
275-
keys: commandToKey[command] != null ? commandToKey[command] : [],
276-
advanced: this.advancedCommands.includes(command),
277-
});
284+
// Default to base command has no keys for "show available commands" menu.
285+
const optionsToKeys = commandToOptionsToKeys[command] ?? { "": [] };
286+
for (const [options, keys] of Object.entries(optionsToKeys)) {
287+
const advanced = this.advancedCommands.includes(command) ||
288+
this.advancedCommands.includes(`${command} ${options}`);
289+
commandGroups[group].push({
290+
command,
291+
description: this.availableCommands[command].description,
292+
keys,
293+
advanced,
294+
options,
295+
});
296+
}
278297
}
279298
}
280299
chrome.storage.session.set({ helpPageData: commandGroups });
@@ -297,7 +316,6 @@ const Commands = {
297316
"scrollToLeft",
298317
"scrollToRight",
299318
"reload",
300-
"hardReload",
301319
"copyCurrentUrl",
302320
"openCopiedUrlInCurrentTab",
303321
"openCopiedUrlInNewTab",
@@ -331,7 +349,13 @@ const Commands = {
331349
"Vomnibar.activateEditUrl",
332350
"Vomnibar.activateEditUrlInNewTab",
333351
],
334-
findCommands: ["enterFindMode", "performFind", "performBackwardsFind"],
352+
findCommands: [
353+
"enterFindMode",
354+
"performFind",
355+
"performBackwardsFind",
356+
"findSelected",
357+
"findSelectedBackwards",
358+
],
335359
historyNavigation: ["goBack", "goForward"],
336360
tabManipulation: [
337361
"createTab",
@@ -374,6 +398,8 @@ const Commands = {
374398
"mergeTabToExistingWindowOnRight",
375399
"mergeTabToExistingWindowAbove",
376400
"mergeTabToExistingWindowBelow",
401+
"findSelected",
402+
"findSelectedBackwards",
377403
"goUp",
378404
"goToRoot",
379405
"LinkHints.activateModeWithQueue",
@@ -394,11 +420,11 @@ const Commands = {
394420
"enterVisualLineMode",
395421
"toggleViewSource",
396422
"passNextKey",
397-
"hardReload",
398423
"setZoom",
399424
"zoomIn",
400425
"zoomOut",
401426
"zoomReset",
427+
"reload hard",
402428
],
403429
};
404430

@@ -417,7 +443,7 @@ const defaultKeyMappings = {
417443
"d": "scrollPageDown",
418444
"u": "scrollPageUp",
419445
"r": "reload",
420-
"R": "hardReload",
446+
"R": "reload hard",
421447
"yy": "copyCurrentUrl",
422448
"p": "openCopiedUrlInCurrentTab",
423449
"P": "openCopiedUrlInNewTab",
@@ -442,6 +468,8 @@ const defaultKeyMappings = {
442468
"/": "enterFindMode",
443469
"n": "performFind",
444470
"N": "performBackwardsFind",
471+
"*": "findSelected",
472+
"#": "findSelectedBackwards",
445473

446474
// Vomnibar
447475
"o": "Vomnibar.activate",
@@ -511,7 +539,6 @@ const commandDescriptions = {
511539
scrollFullPageUp: ["Scroll a full page up"],
512540

513541
reload: ["Reload the page", { background: true }],
514-
hardReload: ["Hard reload the page", { background: true }],
515542
toggleViewSource: ["View page source", { noRepeat: true }],
516543

517544
copyCurrentUrl: ["Copy the current URL to the clipboard", { noRepeat: true }],
@@ -536,6 +563,8 @@ const commandDescriptions = {
536563
enterFindMode: ["Enter find mode", { noRepeat: true }],
537564
performFind: ["Cycle forward to the next find match"],
538565
performBackwardsFind: ["Cycle backward to the previous find match"],
566+
findSelected: ["Find the selected text"],
567+
findSelectedBackwards: ["Find the selected text, searching backwards"],
539568

540569
goPrevious: ["Follow the link labeled previous or <", { noRepeat: true }],
541570
goNext: ["Follow the link labeled next or >", { noRepeat: true }],
@@ -580,9 +609,9 @@ const commandDescriptions = {
580609
moveTabLeft: ["Move tab to the left", { background: true }],
581610
moveTabRight: ["Move tab to the right", { background: true }],
582611

583-
setZoom: ["Set zoom level to a given value. E.g. map zz setZoom 1.5", { background: true }],
584-
zoomIn: ["Increase zoom", { background: true }],
585-
zoomOut: ["Decrease zoom", { background: true }],
612+
setZoom: ["Set zoom", { background: true }],
613+
zoomIn: ["Zoom in", { background: true }],
614+
zoomOut: ["Zoom out", { background: true }],
586615
zoomReset: ["Reset zoom", { background: true }],
587616

588617
"Vomnibar.activate": ["Open URL, bookmark or history entry", { topFrame: true }],

background_scripts/completion_engines.js

+20-1
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,24 @@ class Brave extends BaseEngine {
228228
}
229229
}
230230

231+
// Kagi is a paid ad-free search engine
232+
class Kagi extends BaseEngine {
233+
constructor() {
234+
super({
235+
engineUrl: "https://kagi.com/autosuggest?q=%s",
236+
regexps: ["^https?://www\\.kagi\\.com/"],
237+
example: {
238+
searchUrl: "https://www.kagi.com/search?q=%s",
239+
keyword: "k",
240+
},
241+
});
242+
}
243+
244+
parse(text) {
245+
return JSON.parse(text).map((suggestion) => suggestion.t);
246+
}
247+
}
248+
231249
// On the user-facing documentation page pages/completion_engines.html, these completion search
232250
// engines will be shown to the user in this order.
233251
const CompletionEngines = [
@@ -241,8 +259,9 @@ const CompletionEngines = [
241259
Webster,
242260
Qwant,
243261
Brave,
262+
Kagi,
244263
];
245264

246265
globalThis.CompletionEngines = CompletionEngines;
247266

248-
export { Amazon, Brave, DuckDuckGo, Qwant, Webster };
267+
export { Amazon, Brave, DuckDuckGo, Kagi, Qwant, Webster };

0 commit comments

Comments
 (0)