Skip to content

Commit f6039cc

Browse files
authored
feat(commands): Allow users to define custom omnibar commands (#2358)
* feat(commands): allow users to define custom omnibar commands This introduces `api.addCommand(name, description, action)` to allow users to add their own commands to the omnibar. The implementation involves a message-passing architecture to communicate between the user script context and the sandboxed UI frame: - A new `addCommand` function on the user-facing API stores the command's action function and dispatches a registration event. - The `front.js` content script forwards this event to the `frontend.js` UI script. - The UI script registers the command with the omnibar, creating a proxy action. - When the command is executed, this proxy dispatches an `executeUserCommand` event back to the user script context, which then looks up and runs the original function. * docs: add `addCommand`
1 parent 85463c3 commit f6039cc

File tree

4 files changed

+70
-10
lines changed

4 files changed

+70
-10
lines changed

docs/API.md

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@
104104
* [RUNTIME][100]
105105
* [Parameters][101]
106106
* [Examples][102]
107+
* [addCommand][103]
108+
* [Parameters][104]
109+
* [Examples][105]
107110

108111
## mapkey
109112

@@ -702,6 +705,24 @@ RUNTIME('getTabs', {queryInfo: {currentWindow: true}}, response => {
702705
});
703706
```
704707

708+
## addCommand
709+
710+
Add a command into Omnibar.
711+
712+
### Parameters
713+
714+
* `name` **[string][103]** the name of the command, used as command name in omnibar.
715+
* `description` **[string][103]** a help message to describe the command.
716+
* `jscode` **[function][104]** a Javascript function to be bound. If the command receives an argument, the argument will be passed to the function.
717+
718+
### Examples
719+
720+
```javascript
721+
addCommand("example", "An example command", function(arg) {
722+
console.log("You entered: " + arg);
723+
});
724+
```
725+
705726
[1]: #mapkey
706727

707728
[2]: #parameters
@@ -906,22 +927,28 @@ RUNTIME('getTabs', {queryInfo: {currentWindow: true}}, response => {
906927

907928
[102]: #examples-23
908929

909-
[103]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
930+
[103]: #addcommand
931+
932+
[104]: #parameters-38
933+
934+
[105]: #examples-24
935+
936+
[106]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
910937

911-
[104]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function
938+
[107]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function
912939

913-
[105]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
940+
[108]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
914941

915-
[106]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
942+
[109]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
916943

917-
[107]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
944+
[110]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
918945

919-
[108]: https://developer.mozilla.org/docs/Web/HTML/Element
946+
[111]: https://developer.mozilla.org/docs/Web/HTML/Element
920947

921-
[109]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
948+
[112]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
922949

923-
[110]: https://github.com/brookhong/Surfingkeys/wiki/Register-inline-query
950+
[113]: https://github.com/brookhong/Surfingkeys/wiki/Register-inline-query
924951

925-
[111]: https://developer.mozilla.org/docs/Web/API/Element
952+
[114]: https://developer.mozilla.org/docs/Web/API/Element
926953

927-
[112]: https://github.com/ajaxorg/ace/blob/ec450c03b51aba3724cf90bb133708078d1f3de6/lib/ace/keyboard/vim.js#L927-L1099
954+
[115]: https://github.com/ajaxorg/ace/blob/ec450c03b51aba3724cf90bb133708078d1f3de6/lib/ace/keyboard/vim.js#L927-L1099

src/content_scripts/front.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,13 @@ function createFront(insert, normal, hints, visual, browser) {
494494
vimKeyMap
495495
});
496496
},
497+
addCommand: (name, description) => {
498+
applyUICommand({
499+
action: 'addCommand',
500+
name: name,
501+
description: description
502+
});
503+
},
497504
highlightElement,
498505
hidePopup,
499506
openFinder: () => {
@@ -661,6 +668,10 @@ function createFront(insert, normal, hints, visual, browser) {
661668
visual.emptySelection();
662669
};
663670

671+
_actions["executeUserCommand"] = function(message) {
672+
dispatchSKEvent('user', ['executeUserCommand', message.name, message.args]);
673+
};
674+
664675
var _active = window === top;
665676
_actions['deactivated'] = function(message) {
666677
_active = false;

src/content_scripts/ui/frontend.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,16 @@ const Front = (function() {
454454
_actions['addVimKeyMap'] = function (message) {
455455
self.vimKeyMap = message.vimKeyMap;
456456
};
457+
_actions['addCommand'] = function(message) {
458+
const proxyAction = (...args) => {
459+
self.contentCommand({
460+
action: 'executeUserCommand',
461+
name: message.name,
462+
args: args
463+
});
464+
};
465+
omnibar.command(message.name, message.description, proxyAction);
466+
};
457467
_actions['getUsage'] = function (message) {
458468
// send response in callback from buildUsage
459469
delete message.ack;

src/user_scripts/index.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ function vmapkey(keys, annotation, jscode, options) {
5050
}
5151
}
5252

53+
const userDefinedCommands = {};
54+
function addCommand(name, description, action) {
55+
userDefinedCommands[name] = action;
56+
dispatchSKEvent('front', ['addCommand', name, description]);
57+
}
58+
5359
function map(new_keystroke, old_keystroke, domain, new_annotation) {
5460
dispatchSKEvent('api', ['map', new_keystroke, old_keystroke, domain, new_annotation]);
5561
}
@@ -76,6 +82,11 @@ initSKFunctionListener("user", {
7682
userDefinedFunctions[keys](para);
7783
}
7884
},
85+
executeUserCommand: (name, args) => {
86+
if (userDefinedCommands.hasOwnProperty(name)) {
87+
userDefinedCommands[name](...args);
88+
}
89+
},
7990
getSearchSuggestions: (url, response, request, callbackId, origin) => {
8091
if (functionsToListSuggestions.hasOwnProperty(url)) {
8192
const ret = functionsToListSuggestions[url](response, request);
@@ -138,6 +149,7 @@ const api = {
138149
aceVimMap,
139150
addVimMapKey,
140151
addSearchAlias,
152+
addCommand,
141153
cmap,
142154
imap,
143155
imapkey,

0 commit comments

Comments
 (0)