From 7ec785696e4bc8bda70d4a17b4f4ca166fa6adcd Mon Sep 17 00:00:00 2001 From: Simon Lydell Date: Sun, 11 Oct 2015 11:50:44 +0200 Subject: [PATCH] Update documentation --- documentation/api.md | 438 +++++++++++++++++++++++------------ documentation/commands.md | 4 +- documentation/config-file.md | 3 +- documentation/options.md | 6 + 4 files changed, 297 insertions(+), 154 deletions(-) diff --git a/documentation/api.md b/documentation/api.md index e50f4bb..7926942 100644 --- a/documentation/api.md +++ b/documentation/api.md @@ -16,9 +16,6 @@ VimFx has a public API. It is intended to be used by: VimFx users who use the public API should write a so-called [config file]. -[special options]: options.md#special-options -[config file]: config-file.md - ## Getting the API @@ -37,39 +34,40 @@ Cu.import(apiUrl, {}).getAPI(vimfx => { You might also want to take a look at the [config file bootstrap.js example][bootstrap.js]. -[bootstrap.js]: config-file.md#bootstrapjs - ## API The following sub-sections assume that you store VimFx’s public API in a variable called `vimfx`. -[defaults.coffee]: ../extension/lib/defaults.coffee +### `vimfx.get(pref)` and `vimfx.set(pref, value)` -### `vimfx.get(pref)` +Gets or sets the value of the VimFx pref `pref`. -Gets the value of the VimFx pref `pref`. +You can see all prefs in [defaults.coffee], or by opening [about:config] and +filtering by `extensions.vimfx`. Note that you can also access the [special +options], which may not be accessed in [about:config], using `vimfx.get()` and +`vimfx.set()`—in fact, this is the _only_ way of accessing those options. -You can see all prefs in [defaults.coffee]. +#### `vimfx.get(pref)` -You might also want to read more about the special pref [categories]. +Gets the value of the VimFx pref `pref`. ```js +// Get the value of the Hint chars option: vimfx.get('hint_chars') +// Get all keyboard shortcuts (as a string) for the `f` command: vimfx.get('modes.normal.follow') ``` -[categories]: vimfxgetcategories +#### `vimfx.set(pref, value)` -### `vimfx.set(pref)` - -Sets the value of the VimFx pref `pref`. - -You can see all prefs in [defaults.coffee]. +Sets the value of the VimFx pref `pref` to `value`. ```js +// Set the value of the Hint chars option: vimfx.set('hint_chars', 'abcdefghijklmnopqrstuvwxyz') +// Add yet a keyboard shortcut for the `f` command: vimfx.set('modes.normal.follow', vimfx.get('modes.normal.follow') + ' e'); ``` @@ -77,8 +75,9 @@ vimfx.set('modes.normal.follow', vimfx.get('modes.normal.follow') + ' e'); Creates a new command. -**Note:** This should only be used by users, not by extension authors who wish -to extend VimFx. They should add commands manually to `vimfx.modes` instead. +**Note:** This should only be used by config file users, not by extension +authors who wish to extend VimFx. They should add commands manually to +[`vimfx.modes`] instead. `options`: @@ -89,17 +88,17 @@ to extend VimFx. They should add commands manually to `vimfx.modes` instead. - description: `String`. Shown in the help dialog and VimFx’s settings page in the Add-ons Manager. - mode: `String`. Defaults to `'normal'`. The mode to add the command to. The - value has to be one of the keys of `vimfx.modes`. + value has to be one of the keys of [`vimfx.modes`]. - category: `String`. Defaults to `'misc'` for Normal mode and `''` (uncategorized) otherwise. The category to add the command to. The - value has to be one of the keys of `vimfx.get('categories')`. + value has to be one of the keys of [`vimfx.get('categories')`][categories]. - order: `Number`. Defaults to putting the command at the end of the category. The first of the default commands has the order `100` and then they increase by `100` per command. This allows to put new commands between two already existing ones. -`fn` is called when the command is activated. See the [`vimfx.modes`] -documentation below for more information. +`fn` is called when the command is activated. See the [onInput] documentation +below for more information. Note that you have to give the new command a shortcut in VimFx’s settings page in the Add-ons Manager or set one using `vimfx.set()` to able to use the new @@ -112,21 +111,21 @@ vimfx.addCommand({ }, => { console.log('Hello World!') }) +// Optional: +vimfx.set('custom.mode.normal.hello', 'gö') ``` -[`vimfx.modes`]: #vimfxmodes - ### `vimfx.addOptionOverrides(...rules)` and `vimfx.addKeyOverrides(...rules)` -Takes any number of arguments. Each argument is a rule. The rules are added in -order. The methods may be run multiple times. +These methods take any number of arguments. Each argument is a rule. The rules +are added in order. The methods may be run multiple times. A rule is an `Array` of length 2: -- The first item is a function that returns `true` if the rule should be applied - and `false` if not. This is called the matching function. -- The second item is the value that should be used if the rule is applied. This - is called the override. +1. The first item is a function that returns `true` if the rule should be + applied and `false` if not. This is called the matching function. +2. The second item is the value that should be used if the rule is applied. This + is called the override. The rules are tried in the same order they were added. When a matching rule is found it is applied. No more rules will be applied. @@ -135,12 +134,11 @@ found it is applied. No more rules will be applied. The rules are matched any time the value of a VimFx pref is needed. -The matching function receives a [`location`]-like object. +The matching function receives a [location object]. The override is an object whose keys are VimFx pref names and whose values -override the pref in question. Note that all space-separated prefs are parsed -into arrays of strings. `black_list` and `{prev,next}_patterns` are parsed into -arrays of regular expressions. +override the pref in question. The values should be formatted as in an [options +object]. ```js vimfx.addOptionOverrides( @@ -156,8 +154,8 @@ vimfx.addOptionOverrides( The rules are matched any time you press a key that is not part of the tail of a multi-key shortcut. -The matching function receives a [`location`]-like object as well as the current -mode. +The matching function receives a [location object] as well as the current +mode name (one of the keys of [`vimfx.modes`]). The override is an array of keys which should not activate VimFx commands but be sent to the page. @@ -173,20 +171,17 @@ vimfx.addKeyOverrides( ) ``` -[`location`]: https://developer.mozilla.org/en-US/docs/Web/API/Location - ### `vimfx.on(eventName, listener)` Runs `listener(data)` when `eventName` is fired. -The following events are available: +#### The `load` event -- load: Occurs when opening a new tab or navigating to a new URL. `data`: - An object with the following properties: +Occurs when opening a new tab or navigating to a new URL. The data passed to +listeners is an object with the following properties: - - vim: The current `vim` instance. Note: This is subject to change. See - [vim.coffee] for now. - - location: A [`location`]-like object. +- vim: The current [vim object]. +- location: A [location object]. This can be used to enter a different mode by default on some pages (which can be used to replace the blacklist option). @@ -199,79 +194,212 @@ vimfx.on('load', ({vim, location}) => { }) ``` +#### The `modeChange` event + +Occurs whenever the current mode in any tab changes. The initial entering of the +default mode in new tabs also counts as a mode change. The data passed to +listeners is the current [vim object]. + +```js +vimfx.on('modeChange', vim => { + let mode = vimfx.modes[vim.mode].name() + vim.notify(`Entering mode: ${mode}`) +}) +``` + ### `vimfx.refresh()` -If you make changes to `vimfx.modes` directly you need to call `vimfx.refresh()` -for your changes to take effect. +If you make changes to [`vimfx.modes`] directly you need to call +`vimfx.refresh()` for your changes to take effect. ### `vimfx.modes` -An object whose keys are mode names and whose values are modes. +An object whose keys are mode names and whose values are [mode object]s. + +This is a very low-level part of the API. It allows to: + +- Access all commands and run them. This is the only thing that a config file + user needs it for. + + ```js + let {commands} = vimfx.modes.normal + // Inside a custom command: + commands.tab_new.run(args) + ``` + +- Adding new commands. This is intended to be used by extension authors who wish + to extend VimFx, not config file users. They should use the + `vimfx.addCommand()` helper instead. + + ```js + vimfx.modes.normal.commands.new_command = { + pref: 'extensions.my_extension.mode.normal.new_command', + category: 'misc', + order: 10000, + description: () => translate('mode.normal.new_command'), + run: args => console.log('New command! args:', args) + } + ``` + +- Adding new modes. This is intended to be used by extension authors who wish to + extend VimFx, not config file users. + + ```js + vimfx.modes.new_mode = { + name: () => translate('mode.new_mode'), + order: 10000, + commands: {}, + onEnter(args) {}, + onLeave(args) {}, + onInput(args, match) { + if (match.type === 'full') { + match.command.run(args) + } + return (match.type !== 'none') + }, + } + ``` + +When you’re done modifying `vimfx.modes` directly, you need to call +`vimfx.refresh()`. (That’s taken care of automatically in the +`vimfx.addCommand()` helper.) + +Have a look at [modes.coffee] and [commands.coffee] for more information. + +### `vimfx.get('categories')` + +An object whose keys are category names and whose values are [category object]s. + +```js +let categories = vimfx.get('categories') + +// Add a new category. +categories.custom = { + name: () => 'Custom commands', + order: 10000, +} + +// Swap the order of the Location and Tabs categories. +;[categories.location.order, categories.tabs.order] = + [categories.tabs.order, categories.location.order] +``` + +### Mode object A mode is an object with the follwing properties: -- name: `Function`. Returns a human readable name of the mode used in the help +- name(): `Function`. Returns a human readable name of the mode used in the help dialog and VimFx’s settings page in the Add-ons Manager. -- order: `Number`. The first of the default modes has the order `0` and then +- order: `Number`. The first of the default modes has the order `100` and then they increase by `100` per mode. This allows to put new modes between two already existing ones. -- commands: `Object`. The keys are command names and the values are commands. -- onEnter: `Function`. Called when the mode is entered. -- onLeave: `Function`. Called when the mode is left. -- onInput: `Function`. Called when a key is pressed. +- commands: `Object`. The keys are command names and the values are [command + object]s. +- onEnter(data, ...args): `Function`. Called when the mode is entered. +- onLeave(data): `Function`. Called when the mode is left. +- onInput(data, match): `Function`. Called when a key is pressed. -The `on*` methods are called with an object with the following properties: +#### onEnter, onLeave and onInput -- vim: An object with state for the current tab. Note: This property is - subject to change. For now, have a look at the [vim.coffee]. -- storage: An object unique to the `vim` instance and to the current mode. - Allows to share things between commands of the same mode. +These methods are called with an object (called `data` above) with the following +properties: -The object passed to `onEnter` also has the following properties: +- vim: The current [vim object]. +- storage: An object unique to the current [vim object] and to the current mode. + Allows to share things between commands of the same mode by getting and + setting keys on it. -- args: `Array`. An array of extra arguments passed when entering the mode. +##### onEnter -The object passed to `onInput` also has the following properties: +This method is called with an object as mentioned above, and after that there +may be any number of arguments (`args` in `vim.enterMode(modeName, ...args)`) +that the mode is free to do whatever it wants with. -- event: The `keydown` event that activated the command. Note: This property - is subject to change. -- count: `match.count`. `match` is defined below. +##### onInput -It also receives a `match` as the second argument. A `match` has the following -properties: +The object passed to this method (see above) also has the following properties: + +- isFrameEvent: `Boolean`. `true` if the event occured in web page content, + `false` otherwise (if the event occured in the browser UI). +- count: `Number`. The count for the command. `undefined` if no count. (This is + simply a copy of `match.count`. `match` is defined below.) + +The above object should be passed to commands when running them. The mode is +free to do whatever it wants with the return value (if any) of the commands it +runs. + +It also receives a [match object] as the second argument. + +`onInput` should return `true` if the current keypress should not be passed on +to the browser and web pages, and `false` otherwise. + +### Category object + +A category is an object with the follwing properties: + +- name(): `Function`. Returns a human readable name of the category used in the + help dialog and VimFx’s settings page in the Add-ons Manager. Config file + users adding custom categories could simply return a string; extension authors + are encouraged to look up the name from a locale file. +- order: `Number`. The first of the default categories is the “uncategorized” + category. It has the order `100` and then they increase by `100` per category. + This allows to put new categories between two already existing ones. + +### Command object + +A command is an object with the following properties: + +- pref: `String`. The pref used to store the shortcuts for the command. +- run(args): `Function`. Called when the command is activated. +- description(): `Function`. Returns a description of the command (as a string), + shown in the help dialog and VimFx’s settings page in the Add-ons Manager. +- category: `String`. The category to add the command to. The value has to be + one of the keys of [`vimfx.get('categories')`][categories]. +- order: `Number`. The first of the default commands has the order `100` and + then they increase by `100` per command. This allows to put new commands + between two already existing ones. + +### Match object + +A `match` object has the following properties: - type: `String`. It has one of the following values: - - `'full'`: The current keypress fully matches a command shortcut. - - `'partial'`: The current keypress partially matches a command shortcut. + - `'full'`: The current keypress, together with previous keypresses, fully + matches a command shortcut. + - `'partial'`: The current keypress, together with previous keypresses, + partially matches a command shortcut. - `'count'`: The current keypress is not part of a command shortcut, but is a digit and contributes to the count of a future matched command. - `'none'`: The current keypress is not part of a command shortcut and does not contribute to a count. -- focus: `String` or `null`. The type of currently focused element (_element_) - plus current pressed key (_key_) combo. You might not want to run commands and - suppress the event if this value is anything other than null. It has one of - the following values: +- focus: `String` or `null`. The type of currently focused _element_ plus + current pressed _key_ combo. You might not want to run commands and suppress + the event if this value is anything other than null. It has one of the + following values, depending on what kind of _element_ is focused and which + _key_ was pressed: - `'editable'`: element: a text input or a `contenteditable` element. - key: anything. + key: any pressed key. - `'activatable'`: element: an “activatable” element (link or button). key: see the [`activatable_element_keys`] option. - `'adjustable'`: element: an “adjustable” element (form control or video player). key: see the [`adjustable_element_keys`] option. - `'other'`: element: some other kind of element that can receive keystrokes, - for example an element in fullscreen mode. key: anything. - - `null`: the currently focused element does not appear to respond to - keystrokes in any special way. + for example an element in fullscreen mode. key: any pressed key. + + If none of the above criteria is met, the value is `null`, which means that + the currently focused element does not appear to respond to keystrokes in any + special way. - command: `null` unless `type` is `'full'`. Then it is the matched command. - This command should usually be run at this point. It is suitable to pass on - the object passed to `onInput` to the command. Some modes might choose to add - extra properties to the object first. (That is favored over passing several - arguments, since it makes it easier for the command to in turn pass the same - data it got on to another command, if needed.) + The matched command should usually be run at this point. It is suitable to + pass on the object passed to [onInput] to the command. Some modes might choose + to add extra properties to the object first. (That is favored over passing + several arguments, since it makes it easier for the command to in turn pass + the same data it got on to another command, if needed.) Usually the return value of the command isn’t used, but that’s up to the mode. @@ -288,91 +416,66 @@ properties: shortcut key tree. This is `true` unless the match is part of the tail of a multi-key shortcut. -`onInput` should return `true` if the current keypress should not be passed on -to the browser and web pages, or `false` otherwise. +### Vim object -A command is an object with the following properties: +There is one `vim` object per tab. -- pref: `String`. The pref used to store the shortcuts for the command. -- run: `Function`. Called when the command is activated. -- description: `Function`. Returns a description of the command, shown in the - help dialog and VimFx’s settings page in the Add-ons Manager. -- category: `String`. The category to add the command to. The value has to be - one of the keys of `vimfx.get('categories')`. -- order: `Number`. The first of the default commands has the order `100` and - then they increase by `100` per command. This allows to put new commands - between two already existing ones. +A `vim` object has the following properties: -This allows to access all commands and run them, add new commands manually and -add new modes. +- window: [`Window`]. The current Firefox window object. Most commands + interacting with Firefox’s UI use this. -```js -let {commands} = vimfx.modes.normal -// Inside a custom command: -commands.tab_new.run(args) - -// Add a new command manually: -vimfx.modes.normal.commands.new_command = { - pref: 'extensions.my_extension.mode.normal.new_command', - category: 'misc', - order: 10000, - description: () => translate('mode.normal.new_command'), - run: args => console.log('New command! args:', args) -} +- browser: [`Browser`]. The `browser` that this vim object handles. -// Add a new mode: -vimfx.modes.new_mode = { - name: () => translate('mode.new_mode'), - order: 10000, - commands: {}, - onEnter(args) {}, - onLeave(args) {}, - onInput(args, match) { - if (match.type === 'full') { - match.command.run(args) - } - return (match.type !== 'none') - }, -} +- options: `Object`. Provides access to all of VimFx’s options. It is an + [options object]. -vimfx.refresh() -``` +- mode: `String`. The current mode name. -Have a look at [modes.coffee] and [commands.coffee] for more information. +- enterMode(modeName, ...args): `Function`. Enter mode `modeName`, passing + `...args` to the mode. It is up to every mode to do whatever it wants to with + `...args`. -[`activatable_element_keys`]: options.md#activatable_element_keys -[`adjustable_element_keys`]: options.md#adjustable_element_keys -[vim.coffee]: ../extension/lib/vim.coffee -[modes.coffee]: ../extension/lib/modes.coffee -[commands.coffee]: ../extension/lib/commands.coffee +- isBlacklisted(): `Function`. Returns `true` if the current URL is + [blacklisted], and `false` otherwise. -### `vimfx.get('categories')` +- isFrameEvent(event): `Function`. Returns `true` if `event` occurred in web + page content, and `false` otherwise (if it occurred in Firefox’s UI). -An object whose keys are category names and whose values are categories. +- notify(title, options = {}): `Function`. Display a notification with the title + `title` (a `String`). If you need more text than a title, use `options.body`. + See [`Notification`] for more information. -A category is an object with the follwing properties: +**Warning:** There are also properties starting with an underscore on `vim` +objects. They are private, and not supposed to be used outside of VimFx’s own +source code. They may change at any time. -- name: `Function`. Returns a human readable name of the category used in the - help dialog and VimFx’s settings page in the Add-ons Manager. Users adding - custom category could simply return a string; extension authors are encouraged - to look up the name from a locale file. -- order: `Number`. The first of the default categories is the “uncategorized” - category. It has the order `0` and then they increase by `100` per category. - This allows to put new categories between two already existing ones. +### Options object -```js -let categories = vimfx.get('categories') +An `options` object provides access to all of VimFx’s options. It is an object +whose keys are VimFx pref names. -// Add new category. -categories.custom = { - name: () => 'Custom commands', - order: 10000, -} +Note that the values are not just simply `vimfx.get(pref)` for the `pref` in +question; they are _parsed_ (`parse(vimfx.get(pref))`): + +- Space-separated prefs are parsed into arrays of strings. + +- `black_list` and `{prev,next}_patterns` are parsed into arrays of regular + expressions. + +(See [parse-prefs.coffee] for all details.) + +Any [option overrides] are automatically taken into account when getting an +option value. + +The [special options] are also available on this object. -// Swap the order of the Location and Tabs categories. -;[categories.location.order, categories.tabs.order] = - [categories.tabs.order, categories.location.order] -``` + +### Location object + +A location object is very similar to [`window.location`] in web pages. +Technically, it is a [`URL`] instance. You can experient with the current +location object by opening the [web console] and entering `location`. ## Stability @@ -382,3 +485,36 @@ might break with new VimFx versions. As soon as VimFx 1.0.0 is released backwards compatibility will be a priority and won’t be broken until VimFx 2.0.0. + +[option overrides]: #vimfxaddOptionOverridesrules +[categories]: #vimfxgetcategories +[`vimfx.modes`]: #vimfxmodes +[onInput]: #oninput +[mode object]: #mode-object +[category object]: #category-object +[command object]: #command-object +[match object]: #match-object +[vim object]: #vim-object +[options object]: #options-object +[location object]: #location-object + +[blacklisted]: options.md#blacklist +[special options]: options.md#special-options +[config file]: config-file.md +[bootstrap.js]: config-file.md#bootstrapjs +[`activatable_element_keys`]: options.md#activatable_element_keys +[`adjustable_element_keys`]: options.md#adjustable_element_keys + +[defaults.coffee]: ../extension/lib/defaults.coffee +[parse-prefs.coffee]: ../extension/lib/parse-prefs.coffee +[modes.coffee]: ../extension/lib/modes.coffee +[commands.coffee]: ../extension/lib/commands.coffee +[vim.coffee]: ../extension/lib/vim.coffee + +[`Window`]: https://developer.mozilla.org/en-US/docs/Web/API/Window +[`Browser`]: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/browser +[`Notification`]: https://developer.mozilla.org/en-US/docs/Web/API/Notification +[`window.location`]: https://developer.mozilla.org/en-US/docs/Web/API/Location +[`URL`]: https://developer.mozilla.org/en-US/docs/Web/API/URL +[web console]: https://developer.mozilla.org/en-US/docs/Tools/Web_Console +[about:config]: http://kb.mozillazine.org/About:config diff --git a/documentation/commands.md b/documentation/commands.md index 0d74bcb..498883e 100644 --- a/documentation/commands.md +++ b/documentation/commands.md @@ -53,7 +53,7 @@ Closes the current tab and _count_ minus one of the following tabs. Restores the _count_ last closed tabs. -### `q` +### `I` Passes on the next _count_ keypresses to the page, without activating VimFx commands. @@ -91,7 +91,7 @@ space by default. VimFx provides similar scrolling commands (and actually overrides space), but they work a little bit differently. They scroll _the currently focused element._ If the currently focused element -isn’t scrollable, or there are no (apparent) currently focused element, the +isn’t scrollable, or there is no (apparent) currently focused element, the entire page is scrolled. You can focus scrollable elements using the `zf` command. diff --git a/documentation/config-file.md b/documentation/config-file.md index ec66369..49e2426 100644 --- a/documentation/config-file.md +++ b/documentation/config-file.md @@ -88,6 +88,7 @@ feel like it): true + true 2 @@ -121,7 +122,7 @@ function startup() { Cu.import(apiUrl, {}).getAPI(vimfx => { // Do things with the `vimfx` object between this line - console.log('Hello, word! This is vimfx:', vimfx) + console.log('Hello, world! This is vimfx:', vimfx) // and this line. }) diff --git a/documentation/options.md b/documentation/options.md index 81bf252..0b8a5aa 100644 --- a/documentation/options.md +++ b/documentation/options.md @@ -237,3 +237,9 @@ Manager nor in [about:config]. The only way to change them is by using the See the description of the `translations` option in [vim-like-key-notation]. [vim-like-key-notation]: https://github.com/lydell/vim-like-key-notation#api + +### `categories` + +See the documentation for [`vimfx.get('categories')`][categories]. + +[categories]: api.md#vimfxgetcategories -- 2.39.3