2 This is part of the VimFx documentation.
3 Copyright Simon Lydell 2015.
4 See the file README.md for copying conditions.
9 VimFx has a public API. It is intended to be used by:
11 - Users who prefer to configure things using text files.
12 - Users who would like to add custom commands.
13 - Users who would like to set [special options].
14 - Users who would like to make site-specific customizations.
15 - Extension authors who would like to extend VimFx.
17 VimFx users who use the public API should write a so-called [config file].
23 let {classes: Cc, interfaces: Ci, utils: Cu} = Components
24 Cu.import('resource://gre/modules/Services.jsm')
25 let apiPref = 'extensions.VimFx.api_url'
26 let apiUrl = Services.prefs.getComplexValue(apiPref, Ci.nsISupportsString).data
27 Cu.import(apiUrl, {}).getAPI(vimfx => {
29 // Do things with the `vimfx` object here.
34 You might also want to take a look at the [config file bootstrap.js
35 example][bootstrap.js].
37 Note that the callback passed to `getAPI` is called once every time VimFx starts
38 up, not once per Firefox session! This means that if you update VimFx (or
39 disable and then enable it), the callback is re-run with the new version.
44 The following sub-sections assume that you store VimFx’s public API in a
45 variable called `vimfx`.
47 ### `vimfx.get(pref)`, `vimfx.getDefault(pref)` and `vimfx.set(pref, value)`
49 Gets or sets the (default) value of the VimFx pref `pref`.
51 You can see all prefs in [defaults.coffee], or by opening [about:config] and
52 filtering by `extensions.vimfx`. Note that you can also access the [special
53 options], which may not be accessed in [about:config], using `vimfx.get()` and
54 `vimfx.set()`—in fact, this is the _only_ way of accessing those options.
56 #### `vimfx.get(pref)`
58 Gets the value of the VimFx pref `pref`.
61 // Get the value of the Hint chars option:
62 vimfx.get('hint_chars')
63 // Get all keyboard shortcuts (as a string) for the `f` command:
64 vimfx.get('mode.normal.follow')
67 #### `vimfx.getDefault(pref)`
69 Gets the default value of the VimFx pref `pref`.
71 Useful when you wish to extend a default, rather than replacing it. See below.
73 #### `vimfx.set(pref, value)`
75 Sets the value of the VimFx pref `pref` to `value`.
78 // Set the value of the Hint chars option:
79 vimfx.set('hint_chars', 'abcdefghijklmnopqrstuvwxyz')
80 // Add yet a keyboard shortcut for the `f` command:
81 vimfx.set('mode.normal.follow', vimfx.getDefault('mode.normal.follow') + ' e')
84 When extending a pref (as in the second example above), be sure to use
85 `vimfx.getDefault` rather than `vimfx.get`. Otherwise you get a multiplying
86 effect. In the above example, after starting Firefox a few times the pref would
87 be `f e e e e`. Also, if you find that example very verbose: Remember that
88 you’re using a programming language! Write a small helper function that suits
91 Note: If you produce conflicting keyboard shortcuts, the order of your code does
92 not matter. The command that comes first in VimFx’s settings page in the Add-ons
93 Manager (and in the help dialog) gets the shortcut; the other one(s) do(es) not.
94 See the notes about order in [mode object], [category object] and [command
95 object] for more information about order.
98 // Even though we set the shortcut for focusing the search bar last, the command
99 // for focusing the location bar “wins”, because it comes first in VimFx’s
100 // settings page in the Add-ons Manager.
101 vimfx.set('mode.normal.focus_location_bar', 'ö')
102 vimfx.set('mode.normal.focus_search_bar', 'ö')
104 // Swapping their orders also swaps the “winner”.
105 let {commands} = vimfx.modes.normal
106 ;[commands.focus_location_bar.order, commands.focus_search_bar.order] =
107 [commands.focus_search_bar.order, commands.focus_location_bar.order]
110 ### `vimfx.addCommand(options, fn)`
112 Creates a new command.
114 **Note:** This should only be used by config file users, not by extension
115 authors who wish to extend VimFx. They should add commands manually to
116 [`vimfx.modes`] instead.
120 - name: `String`. The name used when accessing the command via
121 `vimfx.modes[options.mode].commands[options.name]`. It is also used for the
122 pref used to store the shortcuts for the command:
123 `` `custom.mode.${options.mode}.${options.name}` ``.
124 - description: `String`. Shown in the help dialog and VimFx’s settings page in
126 - mode: `String`. Defaults to `'normal'`. The mode to add the command to. The
127 value has to be one of the keys of [`vimfx.modes`].
128 - category: `String`. Defaults to `'misc'` for Normal mode and `''`
129 (uncategorized) otherwise. The category to add the command to. The
130 value has to be one of the keys of [`vimfx.get('categories')`][categories].
131 - order: `Number`. Defaults to putting the command at the end of the category.
132 The first of the default commands has the order `100` and then they increase
133 by `100` per command. This allows to put new commands between two already
136 `fn` is called when the command is activated. See the [onInput] documentation
137 below for more information.
139 Note that you have to give the new command a shortcut in VimFx’s settings page
140 in the Add-ons Manager or set one using `vimfx.set()` to able to use the new
146 description: 'Log Hello World',
148 console.log('Hello World!')
151 vimfx.set('custom.mode.normal.hello', 'gö')
154 ### `vimfx.addOptionOverrides(...rules)` and `vimfx.addKeyOverrides(...rules)`
156 These methods take any number of arguments. Each argument is a rule. The rules
157 are added in order. The methods may be run multiple times.
159 A rule is an `Array` of length 2:
161 1. The first item is a function that returns `true` if the rule should be
162 applied and `false` if not. This is called the matching function.
163 2. The second item is the value that should be used if the rule is applied. This
164 is called the override.
166 The rules are tried in the same order they were added. When a matching rule is
167 found it is applied. No more rules will be applied.
169 #### `vimfx.addOptionOverrides(...rules)`
171 The rules are matched any time the value of a VimFx pref is needed.
173 The matching function receives a [location object].
175 The override is an object whose keys are VimFx pref names and whose values
176 override the pref in question. The values should be formatted as in an [options
180 vimfx.addOptionOverrides(
181 [ ({hostname, pathname, hash}) =>
182 `${hostname}${pathname}${hash}` === 'google.com/',
183 {prevent_autofocus: false}
188 #### `vimfx.addKeyOverrides(...rules)`
190 The rules are matched any time you press a key that is not part of the tail of a
193 The matching function receives a [location object] as well as the current
194 mode name (one of the keys of [`vimfx.modes`]).
196 The override is an array of keys which should not activate VimFx commands but be
199 This allows to disable commands on specific sites. To _add_ commands on specific
200 sites, add them globally and then disable them on all _other_ sites.
203 vimfx.addKeyOverrides(
204 [ location => location.hostname === 'facebook.com',
210 ### `vimfx.on(eventName, listener)`
212 Runs `listener(data)` when `eventName` is fired.
214 #### The `locationChange` event
216 Occurs when opening a new tab, navigating to a new URL or refreshing the page,
217 causing a full page load. The data passed to listeners is an object with the
218 following properties:
220 - vim: The current [vim object].
221 - location: A [location object].
223 This can be used to enter a different mode by default on some pages (which can
224 be used to replace the blacklist option).
227 vimfx.on('locationChange', ({vim, location}) => {
228 if (location.hostname === 'example.com') {
229 vim.enterMode('ignore')
234 #### The `modeChange` event
236 Occurs whenever the current mode in any tab changes. The initial entering of the
237 default mode in new tabs also counts as a mode change. The data passed to
238 listeners is the current [vim object].
241 vimfx.on('modeChange', vim => {
242 let mode = vimfx.modes[vim.mode].name()
243 vim.notify(`Entering mode: ${mode}`)
247 #### The `TabSelect` event
249 Occurs whenever any tab in any window is selected. This is also fired when
250 Firefox starts for the currently selected tab. The data passed to listeners is
251 the `event` object passed to the standard Firefox [TabSelect] event.
253 ### The `modeDisplayChange` event
255 This is basically a combination of the `modeChange` and the `TabSelect` events.
256 The event is useful for knowing when to update UI showing the current mode. (In
257 fact, VimFx itself uses it to update the toolbar [button]!) The data passed to
258 listeners is the current [vim object].
260 You can also highlight the current mode using [styling].
265 An object whose keys are mode names and whose values are [mode object]s.
267 This is a very low-level part of the API. It allows to:
269 - Access all commands and run them. This is the only thing that a config file
273 let {commands} = vimfx.modes.normal
274 // Inside a custom command:
275 commands.tab_new.run(args)
278 - Adding new commands. This is intended to be used by extension authors who wish
279 to extend VimFx, not config file users. They should use the
280 `vimfx.addCommand()` helper instead.
283 vimfx.modes.normal.commands.new_command = {
284 pref: 'extensions.my_extension.mode.normal.new_command',
287 description: () => translate('mode.normal.new_command'),
288 run: args => console.log('New command! args:', args)
292 - Adding new modes. This is intended to be used by extension authors who wish to
293 extend VimFx, not config file users.
296 vimfx.modes.new_mode = {
297 name: () => translate('mode.new_mode'),
302 onInput(args, match) {
303 if (match.type === 'full') {
304 match.command.run(args)
306 return (match.type !== 'none')
311 Have a look at [modes.coffee] and [commands.coffee] for more information.
313 ### `vimfx.get('categories')`
315 An object whose keys are category names and whose values are [category object]s.
318 let categories = vimfx.get('categories')
320 // Add a new category.
321 categories.custom = {
322 name: () => 'Custom commands',
326 // Swap the order of the Location and Tabs categories.
327 ;[commands.focus_location_bar.order, categories.tabs.order] =
328 [categories.tabs.order, commands.focus_location_bar.order]
333 A mode is an object with the follwing properties:
335 - name(): `Function`. Returns a human readable name of the mode used in the help
336 dialog and VimFx’s settings page in the Add-ons Manager.
337 - order: `Number`. The first of the default modes has the order `100` and then
338 they increase by `100` per mode. This allows to put new modes between two
339 already existing ones.
340 - commands: `Object`. The keys are command names and the values are [command
342 - onEnter(data, ...args): `Function`. Called when the mode is entered.
343 - onLeave(data): `Function`. Called when the mode is left.
344 - onInput(data, match): `Function`. Called when a key is pressed.
346 #### onEnter, onLeave and onInput
348 These methods are called with an object (called `data` above) with the following
351 - vim: The current [vim object].
352 - storage: An object unique to the current [vim object] and to the current mode.
353 Allows to share things between commands of the same mode by getting and
358 This method is called with an object as mentioned above, and after that there
359 may be any number of arguments (`args` in `vim.enterMode(modeName, ...args)`)
360 that the mode is free to do whatever it wants with.
362 Whatever is returned from `onEnter` will be returned from
363 `vim.enterMode(modeName, ...args)`.
367 The object passed to this method (see above) also has the following properties:
369 - uiEvent: `Event` or `false`. The keydown event object if the event occured in
370 the browser UI, `false` otherwise (if the event occured in web page content).
371 - count: `Number`. The count for the command. `undefined` if no count. (This is
372 simply a copy of `match.count`. `match` is defined below.)
374 The above object should be passed to commands when running them. The mode is
375 free to do whatever it wants with the return value (if any) of the commands it
378 It also receives a [match object] as the second argument.
380 `onInput` should return `true` if the current keypress should not be passed on
381 to the browser and web pages, and `false` otherwise.
385 A category is an object with the follwing properties:
387 - name(): `Function`. Returns a human readable name of the category used in the
388 help dialog and VimFx’s settings page in the Add-ons Manager. Config file
389 users adding custom categories could simply return a string; extension authors
390 are encouraged to look up the name from a locale file.
391 - order: `Number`. The first of the default categories is the “uncategorized”
392 category. It has the order `100` and then they increase by `100` per category.
393 This allows to put new categories between two already existing ones.
397 A command is an object with the following properties:
399 - pref: `String`. The pref used to store the shortcuts for the command.
400 - run(args): `Function`. Called when the command is activated.
401 - description(): `Function`. Returns a description of the command (as a string),
402 shown in the help dialog and VimFx’s settings page in the Add-ons Manager.
403 - category: `String`. The category to add the command to. The value has to be
404 one of the keys of [`vimfx.get('categories')`][categories].
405 - order: `Number`. The first of the default commands has the order `100` and
406 then they increase by `100` per command. This allows to put new commands
407 between two already existing ones.
411 A `match` object has the following properties:
413 - type: `String`. It has one of the following values:
415 - `'full'`: The current keypress, together with previous keypresses, fully
416 matches a command shortcut.
417 - `'partial'`: The current keypress, together with previous keypresses,
418 partially matches a command shortcut.
419 - `'count'`: The current keypress is not part of a command shortcut, but is a
420 digit and contributes to the count of a future matched command.
421 - `'none'`: The current keypress is not part of a command shortcut and does
422 not contribute to a count.
424 - focus: `String` or `null`. The type of currently focused _element_ plus
425 current pressed _key_ combo. You might not want to run commands and suppress
426 the event if this value is anything other than null. It has one of the
427 following values, depending on what kind of _element_ is focused and which
430 - `'editable'`: element: a text input or a `contenteditable` element.
431 key: any pressed key.
432 - `'activatable'`: element: an “activatable” element (link or button).
433 key: see the [`activatable_element_keys`] option.
434 - `'adjustable'`: element: an “adjustable” element (form control or video
435 player). key: see the [`adjustable_element_keys`] option.
436 - `'other'`: element: some other kind of element that can receive keystrokes,
437 for example an element in fullscreen mode. key: any pressed key.
439 If none of the above criteria is met, the value is `null`, which means that
440 the currently focused element does not appear to respond to keystrokes in any
443 - command: `null` unless `type` is `'full'`. Then it is the matched command (a
446 The matched command should usually be run at this point. It is suitable to
447 pass on the object passed to [onInput] to the command. Some modes might choose
448 to add extra properties to the object first. (That is favored over passing
449 several arguments, since it makes it easier for the command to in turn pass
450 the same data it got on to another command, if needed.)
452 Usually the return value of the command isn’t used, but that’s up to the mode.
454 - count: `Number`. The count for the command. `undefined` if no count.
456 - specialKeys: `Object`. The keys may be any of the following:
461 If a key exists, its value is always `true`. The keys that exist indicate the
462 [special keys] for the sequence used for the matched command (if any).
464 - keyStr: `String`. The current keypress represented as a string.
466 - unmodifiedKey: `String`. `keyStr` without modifiers.
468 - toplevel: `Boolean`. Whether or not the match was a toplevel match in the
469 shortcut key tree. This is `true` unless the match is part of the tail of a
474 There is one `vim` object per tab.
476 A `vim` object has the following properties:
478 - window: [`Window`]. The current Firefox window object. Most commands
479 interacting with Firefox’s UI use this.
481 - browser: [`Browser`]. The `browser` that this vim object handles.
483 - options: `Object`. Provides access to all of VimFx’s options. It is an
486 - mode: `String`. The current mode name.
488 - enterMode(modeName, ...args): `Function`. Enter mode `modeName`, passing
489 `...args` to the mode. It is up to every mode to do whatever it wants to with
490 `...args`. If `modeName` was already the current mode, nothing is done and
491 `undefined` is returned. Otherwise it us up to the mode to return whatever it
494 - isUIEvent(event): `Function`. Returns `true` if `event` occurred in the
495 browser UI, and `false` otherwise (if it occurred in web page content).
497 - notify(title, options = {}): `Function`. Display a notification with the title
498 `title` (a `String`). If you need more text than a title, use `options.body`.
499 See [`Notification`] for more information.
501 - markPageInteraction(): `Function`. Marks that the user has interacted with the
502 page. After that [autofocus prevention] is not done anymore. Commands
503 interacting with web page content might want to do this.
505 **Warning:** There are also properties starting with an underscore on `vim`
506 objects. They are private, and not supposed to be used outside of VimFx’s own
507 source code. They may change at any time.
511 An `options` object provides access to all of VimFx’s options. It is an object
512 whose keys are VimFx pref names.
514 Note that the values are not just simply `vimfx.get(pref)` for the `pref` in
515 question; they are _parsed_ (`parse(vimfx.get(pref))`):
517 - Space-separated prefs are parsed into arrays of strings.
519 - `black_list` and `{prev,next}_patterns` are parsed into arrays of regular
522 (See [parse-prefs.coffee] for all details.)
524 Any [option overrides] are automatically taken into account when getting an
527 The [special options] are also available on this object.
532 A location object is very similar to [`window.location`] in web pages.
533 Technically, it is a [`URL`] instance. You can experient with the current
534 location object by opening the [web console] and entering `location`.
539 The public API is currently **experimental** and therefore **unstable.** Things
540 might break with new VimFx versions. However, no breaking changes are planned,
541 and will be avoided if feasible.
543 As soon as VimFx 1.0.0 (which does not seem to be too far away) is released
544 backwards compatibility will be a priority and won’t be broken until VimFx
547 [option overrides]: #vimfxaddoptionoverridesrules
548 [categories]: #vimfxgetcategories
549 [`vimfx.modes`]: #vimfxmodes
551 [mode object]: #mode-object
552 [category object]: #category-object
553 [command object]: #command-object
554 [match object]: #match-object
555 [vim object]: #vim-object
556 [options object]: #options-object
557 [location object]: #location-object
559 [blacklisted]: options.md#blacklist
560 [special options]: options.md#special-options
561 [config file]: config-file.md
562 [bootstrap.js]: config-file.md#bootstrapjs
563 [autofocus prevention]: options.md#prevent-autofocus
564 [`activatable_element_keys`]: options.md#activatable_element_keys
565 [`adjustable_element_keys`]: options.md#adjustable_element_keys
568 [special keys]: shortcuts.md#special-keys
569 [styling]: styling.md
571 [defaults.coffee]: ../extension/lib/defaults.coffee
572 [parse-prefs.coffee]: ../extension/lib/parse-prefs.coffee
573 [modes.coffee]: ../extension/lib/modes.coffee
574 [commands.coffee]: ../extension/lib/commands.coffee
575 [vim.coffee]: ../extension/lib/vim.coffee
577 [`Window`]: https://developer.mozilla.org/en-US/docs/Web/API/Window
578 [`Browser`]: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/browser
579 [`Notification`]: https://developer.mozilla.org/en-US/docs/Web/API/Notification
580 [`window.location`]: https://developer.mozilla.org/en-US/docs/Web/API/Location
581 [`URL`]: https://developer.mozilla.org/en-US/docs/Web/API/URL
582 [TabSelect]: https://developer.mozilla.org/en-US/docs/Web/Events/TabSelect
583 [web console]: https://developer.mozilla.org/en-US/docs/Tools/Web_Console
584 [about:config]: http://kb.mozillazine.org/About:config