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].
40 The following sub-sections assume that you store VimFx’s public API in a
41 variable called `vimfx`.
43 ### `vimfx.get(pref)` and `vimfx.set(pref, value)`
45 Gets or sets the value of the VimFx pref `pref`.
47 You can see all prefs in [defaults.coffee], or by opening [about:config] and
48 filtering by `extensions.vimfx`. Note that you can also access the [special
49 options], which may not be accessed in [about:config], using `vimfx.get()` and
50 `vimfx.set()`—in fact, this is the _only_ way of accessing those options.
52 #### `vimfx.get(pref)`
54 Gets the value of the VimFx pref `pref`.
57 // Get the value of the Hint chars option:
58 vimfx.get('hint_chars')
59 // Get all keyboard shortcuts (as a string) for the `f` command:
60 vimfx.get('modes.normal.follow')
63 #### `vimfx.set(pref, value)`
65 Sets the value of the VimFx pref `pref` to `value`.
68 // Set the value of the Hint chars option:
69 vimfx.set('hint_chars', 'abcdefghijklmnopqrstuvwxyz')
70 // Add yet a keyboard shortcut for the `f` command:
71 vimfx.set('modes.normal.follow', vimfx.get('modes.normal.follow') + ' e')
74 Note: If you produce conflicting keyboard shortcuts, the order of your code does
75 not matter. The command that comes first in VimFx’s settings page in the Add-ons
76 Manager (and in the help dialog) gets the shortcut; the other one(s) do(es) not.
77 See the notes about order in [mode object], [category object] and [command
78 object] for more information about order.
81 // Even though we set the shortcut for focusing the search bar last, the command
82 // for focusing the location bar “wins”, because it comes first in VimFx’s
83 // settings page in the Add-ons Manager.
84 vimfx.set('modes.normal.focus_location_bar', 'ö')
85 vimfx.set('modes.normal.focus_search_bar', 'ö')
87 // Swapping their orders also swaps the “winner”.
88 let {commands} = vimfx.modes.normal
89 ;[commands.focus_location_bar.order, commands.focus_search_bar.order] =
90 [commands.focus_search_bar.order, commands.focus_location_bar.order]
93 ### `vimfx.addCommand(options, fn)`
95 Creates a new command.
97 **Note:** This should only be used by config file users, not by extension
98 authors who wish to extend VimFx. They should add commands manually to
99 [`vimfx.modes`] instead.
103 - name: `String`. The name used when accessing the command via
104 `vimfx.modes[options.mode].commands[options.name]`. It is also used for the
105 pref used to store the shortcuts for the command:
106 `` `custom.mode.${options.mode}.${options.name}` ``.
107 - description: `String`. Shown in the help dialog and VimFx’s settings page in
109 - mode: `String`. Defaults to `'normal'`. The mode to add the command to. The
110 value has to be one of the keys of [`vimfx.modes`].
111 - category: `String`. Defaults to `'misc'` for Normal mode and `''`
112 (uncategorized) otherwise. The category to add the command to. The
113 value has to be one of the keys of [`vimfx.get('categories')`][categories].
114 - order: `Number`. Defaults to putting the command at the end of the category.
115 The first of the default commands has the order `100` and then they increase
116 by `100` per command. This allows to put new commands between two already
119 `fn` is called when the command is activated. See the [onInput] documentation
120 below for more information.
122 Note that you have to give the new command a shortcut in VimFx’s settings page
123 in the Add-ons Manager or set one using `vimfx.set()` to able to use the new
129 description: 'Log Hello World',
131 console.log('Hello World!')
134 vimfx.set('custom.mode.normal.hello', 'gö')
137 ### `vimfx.addOptionOverrides(...rules)` and `vimfx.addKeyOverrides(...rules)`
139 These methods take any number of arguments. Each argument is a rule. The rules
140 are added in order. The methods may be run multiple times.
142 A rule is an `Array` of length 2:
144 1. The first item is a function that returns `true` if the rule should be
145 applied and `false` if not. This is called the matching function.
146 2. The second item is the value that should be used if the rule is applied. This
147 is called the override.
149 The rules are tried in the same order they were added. When a matching rule is
150 found it is applied. No more rules will be applied.
152 #### `vimfx.addOptionOverrides(...rules)`
154 The rules are matched any time the value of a VimFx pref is needed.
156 The matching function receives a [location object].
158 The override is an object whose keys are VimFx pref names and whose values
159 override the pref in question. The values should be formatted as in an [options
163 vimfx.addOptionOverrides(
164 [ ({hostname, pathname, hash}) =>
165 `${hostname}${pathname}${hash}` === 'google.com/',
166 {prevent_autofocus: false}
171 #### `vimfx.addKeyOverrides(...rules)`
173 The rules are matched any time you press a key that is not part of the tail of a
176 The matching function receives a [location object] as well as the current
177 mode name (one of the keys of [`vimfx.modes`]).
179 The override is an array of keys which should not activate VimFx commands but be
182 This allows to disable commands on specific sites. To _add_ commands on specific
183 sites, add them globally and then disable them on all _other_ sites.
186 vimfx.addKeyOverrides(
187 [ location => location.hostname === 'facebook.com',
193 ### `vimfx.on(eventName, listener)`
195 Runs `listener(data)` when `eventName` is fired.
197 #### The `load` event
199 Occurs when opening a new tab or navigating to a new URL. The data passed to
200 listeners is an object with the following properties:
202 - vim: The current [vim object].
203 - location: A [location object].
205 This can be used to enter a different mode by default on some pages (which can
206 be used to replace the blacklist option).
209 vimfx.on('load', ({vim, location}) => {
210 if (location.hostname === 'example.com') {
211 vim.enterMode('ignore')
216 #### The `modeChange` event
218 Occurs whenever the current mode in any tab changes. The initial entering of the
219 default mode in new tabs also counts as a mode change. The data passed to
220 listeners is the current [vim object].
223 vimfx.on('modeChange', vim => {
224 let mode = vimfx.modes[vim.mode].name()
225 vim.notify(`Entering mode: ${mode}`)
229 ### `vimfx.refresh()`
231 If you make changes to [`vimfx.modes`] directly you need to call
232 `vimfx.refresh()` for your changes to take effect.
236 An object whose keys are mode names and whose values are [mode object]s.
238 This is a very low-level part of the API. It allows to:
240 - Access all commands and run them. This is the only thing that a config file
244 let {commands} = vimfx.modes.normal
245 // Inside a custom command:
246 commands.tab_new.run(args)
249 - Adding new commands. This is intended to be used by extension authors who wish
250 to extend VimFx, not config file users. They should use the
251 `vimfx.addCommand()` helper instead.
254 vimfx.modes.normal.commands.new_command = {
255 pref: 'extensions.my_extension.mode.normal.new_command',
258 description: () => translate('mode.normal.new_command'),
259 run: args => console.log('New command! args:', args)
263 - Adding new modes. This is intended to be used by extension authors who wish to
264 extend VimFx, not config file users.
267 vimfx.modes.new_mode = {
268 name: () => translate('mode.new_mode'),
273 onInput(args, match) {
274 if (match.type === 'full') {
275 match.command.run(args)
277 return (match.type !== 'none')
282 When you’re done modifying `vimfx.modes` directly, you need to call
283 `vimfx.refresh()`. (That’s taken care of automatically in the
284 `vimfx.addCommand()` helper.)
286 Have a look at [modes.coffee] and [commands.coffee] for more information.
288 ### `vimfx.get('categories')`
290 An object whose keys are category names and whose values are [category object]s.
293 let categories = vimfx.get('categories')
295 // Add a new category.
296 categories.custom = {
297 name: () => 'Custom commands',
301 // Swap the order of the Location and Tabs categories.
302 ;[commands.focus_location_bar.order, categories.tabs.order] =
303 [categories.tabs.order, commands.focus_location_bar.order]
308 A mode is an object with the follwing properties:
310 - name(): `Function`. Returns a human readable name of the mode used in the help
311 dialog and VimFx’s settings page in the Add-ons Manager.
312 - order: `Number`. The first of the default modes has the order `100` and then
313 they increase by `100` per mode. This allows to put new modes between two
314 already existing ones.
315 - commands: `Object`. The keys are command names and the values are [command
317 - onEnter(data, ...args): `Function`. Called when the mode is entered.
318 - onLeave(data): `Function`. Called when the mode is left.
319 - onInput(data, match): `Function`. Called when a key is pressed.
321 #### onEnter, onLeave and onInput
323 These methods are called with an object (called `data` above) with the following
326 - vim: The current [vim object].
327 - storage: An object unique to the current [vim object] and to the current mode.
328 Allows to share things between commands of the same mode by getting and
333 This method is called with an object as mentioned above, and after that there
334 may be any number of arguments (`args` in `vim.enterMode(modeName, ...args)`)
335 that the mode is free to do whatever it wants with.
339 The object passed to this method (see above) also has the following properties:
341 - isFrameEvent: `Boolean`. `true` if the event occured in web page content,
342 `false` otherwise (if the event occured in the browser UI).
343 - count: `Number`. The count for the command. `undefined` if no count. (This is
344 simply a copy of `match.count`. `match` is defined below.)
346 The above object should be passed to commands when running them. The mode is
347 free to do whatever it wants with the return value (if any) of the commands it
350 It also receives a [match object] as the second argument.
352 `onInput` should return `true` if the current keypress should not be passed on
353 to the browser and web pages, and `false` otherwise.
357 A category is an object with the follwing properties:
359 - name(): `Function`. Returns a human readable name of the category used in the
360 help dialog and VimFx’s settings page in the Add-ons Manager. Config file
361 users adding custom categories could simply return a string; extension authors
362 are encouraged to look up the name from a locale file.
363 - order: `Number`. The first of the default categories is the “uncategorized”
364 category. It has the order `100` and then they increase by `100` per category.
365 This allows to put new categories between two already existing ones.
369 A command is an object with the following properties:
371 - pref: `String`. The pref used to store the shortcuts for the command.
372 - run(args): `Function`. Called when the command is activated.
373 - description(): `Function`. Returns a description of the command (as a string),
374 shown in the help dialog and VimFx’s settings page in the Add-ons Manager.
375 - category: `String`. The category to add the command to. The value has to be
376 one of the keys of [`vimfx.get('categories')`][categories].
377 - order: `Number`. The first of the default commands has the order `100` and
378 then they increase by `100` per command. This allows to put new commands
379 between two already existing ones.
383 A `match` object has the following properties:
385 - type: `String`. It has one of the following values:
387 - `'full'`: The current keypress, together with previous keypresses, fully
388 matches a command shortcut.
389 - `'partial'`: The current keypress, together with previous keypresses,
390 partially matches a command shortcut.
391 - `'count'`: The current keypress is not part of a command shortcut, but is a
392 digit and contributes to the count of a future matched command.
393 - `'none'`: The current keypress is not part of a command shortcut and does
394 not contribute to a count.
396 - focus: `String` or `null`. The type of currently focused _element_ plus
397 current pressed _key_ combo. You might not want to run commands and suppress
398 the event if this value is anything other than null. It has one of the
399 following values, depending on what kind of _element_ is focused and which
402 - `'editable'`: element: a text input or a `contenteditable` element.
403 key: any pressed key.
404 - `'activatable'`: element: an “activatable” element (link or button).
405 key: see the [`activatable_element_keys`] option.
406 - `'adjustable'`: element: an “adjustable” element (form control or video
407 player). key: see the [`adjustable_element_keys`] option.
408 - `'other'`: element: some other kind of element that can receive keystrokes,
409 for example an element in fullscreen mode. key: any pressed key.
411 If none of the above criteria is met, the value is `null`, which means that
412 the currently focused element does not appear to respond to keystrokes in any
415 - command: `null` unless `type` is `'full'`. Then it is the matched command (a
418 The matched command should usually be run at this point. It is suitable to
419 pass on the object passed to [onInput] to the command. Some modes might choose
420 to add extra properties to the object first. (That is favored over passing
421 several arguments, since it makes it easier for the command to in turn pass
422 the same data it got on to another command, if needed.)
424 Usually the return value of the command isn’t used, but that’s up to the mode.
426 - count: `Number`. The count for the command. `undefined` if no count.
428 - force: `Boolean`. Indicates if the current key sequence started with
431 - keyStr: `String`. The current keypress represented as a string.
433 - unmodifiedKey: `String`. `keyStr` without modifiers.
435 - toplevel: `Boolean`. Whether or not the match was a toplevel match in the
436 shortcut key tree. This is `true` unless the match is part of the tail of a
441 There is one `vim` object per tab.
443 A `vim` object has the following properties:
445 - window: [`Window`]. The current Firefox window object. Most commands
446 interacting with Firefox’s UI use this.
448 - browser: [`Browser`]. The `browser` that this vim object handles.
450 - options: `Object`. Provides access to all of VimFx’s options. It is an
453 - mode: `String`. The current mode name.
455 - enterMode(modeName, ...args): `Function`. Enter mode `modeName`, passing
456 `...args` to the mode. It is up to every mode to do whatever it wants to with
459 - isBlacklisted(): `Function`. Returns `true` if the current URL is
460 [blacklisted], and `false` otherwise.
462 - isFrameEvent(event): `Function`. Returns `true` if `event` occurred in web
463 page content, and `false` otherwise (if it occurred in Firefox’s UI).
465 - notify(title, options = {}): `Function`. Display a notification with the title
466 `title` (a `String`). If you need more text than a title, use `options.body`.
467 See [`Notification`] for more information.
469 **Warning:** There are also properties starting with an underscore on `vim`
470 objects. They are private, and not supposed to be used outside of VimFx’s own
471 source code. They may change at any time.
475 An `options` object provides access to all of VimFx’s options. It is an object
476 whose keys are VimFx pref names.
478 Note that the values are not just simply `vimfx.get(pref)` for the `pref` in
479 question; they are _parsed_ (`parse(vimfx.get(pref))`):
481 - Space-separated prefs are parsed into arrays of strings.
483 - `black_list` and `{prev,next}_patterns` are parsed into arrays of regular
486 (See [parse-prefs.coffee] for all details.)
488 Any [option overrides] are automatically taken into account when getting an
491 The [special options] are also available on this object.
496 A location object is very similar to [`window.location`] in web pages.
497 Technically, it is a [`URL`] instance. You can experient with the current
498 location object by opening the [web console] and entering `location`.
503 The public API is currently **experimental** and therefore **unstable.** Things
504 might break with new VimFx versions.
506 As soon as VimFx 1.0.0 is released backwards compatibility will be a priority
507 and won’t be broken until VimFx 2.0.0.
509 [option overrides]: #vimfxaddOptionOverridesrules
510 [categories]: #vimfxgetcategories
511 [`vimfx.modes`]: #vimfxmodes
513 [mode object]: #mode-object
514 [category object]: #category-object
515 [command object]: #command-object
516 [match object]: #match-object
517 [vim object]: #vim-object
518 [options object]: #options-object
519 [location object]: #location-object
521 [blacklisted]: options.md#blacklist
522 [special options]: options.md#special-options
523 [config file]: config-file.md
524 [bootstrap.js]: config-file.md#bootstrapjs
525 [`activatable_element_keys`]: options.md#activatable_element_keys
526 [`adjustable_element_keys`]: options.md#adjustable_element_keys
528 [defaults.coffee]: ../extension/lib/defaults.coffee
529 [parse-prefs.coffee]: ../extension/lib/parse-prefs.coffee
530 [modes.coffee]: ../extension/lib/modes.coffee
531 [commands.coffee]: ../extension/lib/commands.coffee
532 [vim.coffee]: ../extension/lib/vim.coffee
534 [`Window`]: https://developer.mozilla.org/en-US/docs/Web/API/Window
535 [`Browser`]: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/browser
536 [`Notification`]: https://developer.mozilla.org/en-US/docs/Web/API/Notification
537 [`window.location`]: https://developer.mozilla.org/en-US/docs/Web/API/Location
538 [`URL`]: https://developer.mozilla.org/en-US/docs/Web/API/URL
539 [web console]: https://developer.mozilla.org/en-US/docs/Tools/Web_Console
540 [about:config]: http://kb.mozillazine.org/About:config