]> git.gir.st - VimFx.git/blob - documentation/api.md
Replace `vimfx.categories` with `vimfx.get('categories')`
[VimFx.git] / documentation / api.md
1 <!--
2 This is part of the VimFx documentation.
3 Copyright Simon Lydell 2015.
4 See the file README.md for copying conditions.
5 -->
6
7 # Public API
8
9 VimFx has a public API. It is intended to be used by:
10
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.
16
17 VimFx users who use the public API should write a so-called [config file].
18
19 [special options]: options.md#special-options
20 [config file]: config-file.md
21
22
23 ## Getting the API
24
25 ```js
26 Components.utils.import('resource://gre/modules/Services.jsm')
27 let api_url = Services.prefs.getCharPref('extensions.VimFx.api_url')
28 Components.utils.import(api_url, {}).getAPI(vimfx => {
29
30 // Do things with the `vimfx` object here.
31
32 })
33 ```
34
35 You might also want to take a look at the [config file bootstrap.js
36 example][bootstrap.js].
37
38 [bootstrap.js]: config-file.md#bootstrapjs
39
40
41 ## API
42
43 The following sub-sections assume that you store VimFx’s public API in a
44 variable called `vimfx`.
45
46 [defaults.coffee]: ../extension/lib/defaults.coffee
47
48 ### `vimfx.get(pref)`
49
50 Gets the value of the VimFx pref `pref`.
51
52 You can see all prefs in [defaults.coffee].
53
54 You might also want to read more about the special pref [categories].
55
56 ```js
57 vimfx.get('hint_chars')
58 vimfx.get('modes.normal.follow')
59 ```
60
61 [categories]: vimfxgetcategories
62
63 ### `vimfx.set(pref)`
64
65 Sets the value of the VimFx pref `pref`.
66
67 You can see all prefs in [defaults.coffee].
68
69 ```js
70 vimfx.set('hint_chars', 'abcdefghijklmnopqrstuvwxyz')
71 vimfx.set('modes.normal.follow', vimfx.get('modes.normal.follow') + ' e');
72 ```
73
74 ### `vimfx.addCommand(options, fn)`
75
76 Creates a new command.
77
78 **Note:** This should only be used by users, not by extension authors who wish
79 to extend VimFx. They should add commands manually to `vimfx.modes` instead.
80
81 `options`:
82
83 - name: `String`. The name used when accessing the command via
84 `vimfx.modes[options.mode].commands[options.name]`. It is also used for the
85 pref used to store the shortcuts for the command:
86 `` `custom.mode.${options.mode}.${options.name}` ``.
87 - description: `String`. Shown in the help dialog and VimFx’s settings page in
88 the Add-ons Manager.
89 - mode: `String`. Defaults to `'normal'`. The mode to add the command to. The
90 value has to be one of the keys of `vimfx.modes`.
91 - category: `String`. Defaults to `'misc'` for Normal mode and `''`
92 (uncategorized) otherwise. The category to add the command to. The
93 value has to be one of the keys of `vimfx.get('categories')`.
94 - order: `Number`. Defaults to putting the command at the end of the category.
95 The first of the default commands has the order `100` and then they increase
96 by `100` per command. This allows to put new commands between two already
97 existing ones.
98
99 `fn` is called when the command is activated. See the [`vimfx.modes`]
100 documentation below for more information.
101
102 Note that you have to give the new command a shortcut in VimFx’s settings page
103 in the Add-ons Manager or set one using `vimfx.set()` to able to use the new
104 command.
105
106 ```js
107 vimfx.addCommand({
108 name: 'hello',
109 description: 'Log Hello World',
110 }, => {
111 console.log('Hello World!')
112 })
113 ```
114
115 [`vimfx.modes`]: #vimfxmodes
116
117 ### `vimfx.addOptionOverrides(...rules)` and `vimfx.addKeyOverrides(...rules)`
118
119 Takes any number of arguments. Each argument is a rule. The rules are added in
120 order. The methods may be run multiple times.
121
122 A rule is an `Array` of length 2:
123
124 - The first item is a function that returns `true` if the rule should be applied
125 and `false` if not. This is called the matching function.
126 - The second item is the value that should be used if the rule is applied. This
127 is called the override.
128
129 The rules are tried in the same order they were added. When a matching rule is
130 found it is applied. No more rules will be applied.
131
132 #### `vimfx.addOptionOverrides(...rules)`
133
134 The rules are matched any time the value of a VimFx pref is needed.
135
136 The matching function receives a [`location`]-like object.
137
138 The override is an object whose keys are VimFx pref names and whose values
139 override the pref in question. Note that all space-separated prefs are parsed
140 into arrays of strings. `black_list` and `{prev,next}_patterns` are parsed into
141 arrays of regular expressions.
142
143 ```js
144 vimfx.addOptionOverrides(
145 [ ({hostname, pathname, hash}) =>
146 `${hostname}${pathname}${hash}` === 'google.com/',
147 {prevent_autofocus: false}
148 ]
149 )
150 ```
151
152 #### `vimfx.addKeyOverrides(...rules)`
153
154 The rules are matched any time you press a key that is not part of the tail of a
155 multi-key shortcut.
156
157 The matching function receives a [`location`]-like object as well as the current
158 mode.
159
160 The override is an array of keys which should not activate VimFx commands but be
161 sent to the page.
162
163 This allows to disable commands on specific sites. To _add_ commands on specific
164 sites, add them globally and then disable them on all _other_ sites.
165
166 ```js
167 vimfx.addKeyOverrides(
168 [ location => location.hostname === 'facebook.com',
169 ['j', 'k']
170 ]
171 )
172 ```
173
174 [`location`]: https://developer.mozilla.org/en-US/docs/Web/API/Location
175
176 ### `vimfx.on(eventName, listener)`
177
178 Runs `listener(data)` when `eventName` is fired.
179
180 The following events are available:
181
182 - load: Occurs when opening a new tab or navigating to a new URL. `data`:
183 An object with the following properties:
184
185 - vim: The current `vim` instance. Note: This is subject to change. See
186 [vim.coffee] for now.
187 - location: A [`location`]-like object.
188
189 This can be used to enter a different mode by default on some pages (which can
190 be used to replace the blacklist option).
191
192 ```js
193 vimfx.on('load', ({vim, location}) => {
194 if (location.hostname === 'example.com') {
195 vim.enterMode('ignore')
196 }
197 })
198 ```
199
200 ### `vimfx.refresh()`
201
202 If you make changes to `vimfx.modes` directly you need to call `vimfx.refresh()`
203 for your changes to take effect.
204
205 ### `vimfx.modes`
206
207 An object whose keys are mode names and whose values are modes.
208
209 A mode is an object with the follwing properties:
210
211 - name: `Function`. Returns a human readable name of the mode used in the help
212 dialog and VimFx’s settings page in the Add-ons Manager.
213 - order: `Number`. The first of the default modes has the order `0` and then
214 they increase by `100` per mode. This allows to put new modes between two
215 already existing ones.
216 - commands: `Object`. The keys are command names and the values are commands.
217 - onEnter: `Function`. Called when the mode is entered.
218 - onLeave: `Function`. Called when the mode is left.
219 - onInput: `Function`. Called when a key is pressed.
220
221 The `on*` methods are called with an object with the following properties:
222
223 - vim: An object with state for the current tab. Note: This property is
224 subject to change. For now, have a look at the [vim.coffee].
225 - storage: An object unique to the `vim` instance and to the current mode.
226 Allows to share things between commands of the same mode.
227
228 The object passed to `onEnter` also has the following properties:
229
230 - args: `Array`. An array of extra arguments passed when entering the mode.
231
232 The object passed to `onInput` also has the following properties:
233
234 - event: The `keydown` event that activated the command. Note: This property
235 is subject to change.
236 - count: `match.count`. `match` is defined below.
237
238 It also receives a `match` as the second argument. A `match` has the following
239 properties:
240
241 - type: `String`. It has one of the following values:
242
243 - `'full'`: The current keypress fully matches a command shortcut.
244 - `'partial'`: The current keypress partially matches a command shortcut.
245 - `'count'`: The current keypress is not part of a command shortcut, but is a
246 digit and contributes to the count of a future matched command.
247 - `'none'`: The current keypress is not part of a command shortcut and does
248 not contribute to a count.
249
250 - focus: `String` or `null`. The type of currently focused element (_element_)
251 plus current pressed key (_key_) combo. You might not want to run commands and
252 suppress the event if this value is anything other than null. It has one of
253 the following values:
254
255 - `'editable'`: element: a text input or a `contenteditable` element.
256 key: anything.
257 - `'activatable'`: element: an “activatable” element (link or button).
258 key: see the [`activatable_element_keys`] option.
259 - `'adjustable'`: element: an “adjustable” element (form control or video
260 player). key: see the [`adjustable_element_keys`] option.
261 - `'other'`: element: some other kind of element that can receive keystrokes,
262 for example an element in fullscreen mode. key: anything.
263 - `null`: the currently focused element does not appear to respond to
264 keystrokes in any special way.
265
266 - command: `null` unless `type` is `'full'`. Then it is the matched command.
267
268 This command should usually be run at this point. It is suitable to pass on
269 the object passed to `onInput` to the command. Some modes might choose to add
270 extra properties to the object first. (That is favored over passing several
271 arguments, since it makes it easier for the command to in turn pass the same
272 data it got on to another command, if needed.)
273
274 Usually the return value of the command isn’t used, but that’s up to the mode.
275
276 - count: `Number`. The count for the command. `undefined` if no count.
277
278 - force: `Boolean`. Indicates if the current key sequence started with
279 `<force>`.
280
281 - keyStr: `String`. The current keypress represented as a string.
282
283 - unmodifiedKey: `String`. `keyStr` without modifiers.
284
285 - toplevel: `Boolean`. Whether or not the match was a toplevel match in the
286 shortcut key tree. This is `true` unless the match is part of the tail of a
287 multi-key shortcut.
288
289 `onInput` should return `true` if the current keypress should not be passed on
290 to the browser and web pages, or `false` otherwise.
291
292 A command is an object with the following properties:
293
294 - pref: `String`. The pref used to store the shortcuts for the command.
295 - run: `Function`. Called when the command is activated.
296 - description: `Function`. Returns a description of the command, shown in the
297 help dialog and VimFx’s settings page in the Add-ons Manager.
298 - category: `String`. The category to add the command to. The value has to be
299 one of the keys of `vimfx.get('categories')`.
300 - order: `Number`. The first of the default commands has the order `100` and
301 then they increase by `100` per command. This allows to put new commands
302 between two already existing ones.
303
304 This allows to access all commands and run them, add new commands manually and
305 add new modes.
306
307 ```js
308 let {commands} = vimfx.modes.normal
309 // Inside a custom command:
310 commands.tab_new.run(args)
311
312 // Add a new command manually:
313 vimfx.modes.normal.commands.new_command = {
314 pref: 'extensions.my_extension.mode.normal.new_command',
315 category: 'misc',
316 order: 10000,
317 description: () => translate('mode.normal.new_command'),
318 run: args => console.log('New command! args:', args)
319 }
320
321 // Add a new mode:
322 vimfx.modes.new_mode = {
323 name: () => translate('mode.new_mode'),
324 order: 10000,
325 commands: {},
326 onEnter(args) {},
327 onLeave(args) {},
328 onInput(args, match) {
329 if (match.type === 'full') {
330 match.command.run(args)
331 }
332 return (match.type !== 'none')
333 },
334 }
335
336 vimfx.refresh()
337 ```
338
339 Have a look at [modes.coffee] and [commands.coffee] for more information.
340
341 [`activatable_element_keys`]: options.md#activatable_element_keys
342 [`adjustable_element_keys`]: options.md#adjustable_element_keys
343 [vim.coffee]: ../extension/lib/vim.coffee
344 [modes.coffee]: ../extension/lib/modes.coffee
345 [commands.coffee]: ../extension/lib/commands.coffee
346
347 ### `vimfx.get('categories')`
348
349 An object whose keys are category names and whose values are categories.
350
351 A category is an object with the follwing properties:
352
353 - name: `Function`. Returns a human readable name of the category used in the
354 help dialog and VimFx’s settings page in the Add-ons Manager. Users adding
355 custom category could simply return a string; extension authors are encouraged
356 to look up the name from a locale file.
357 - order: `Number`. The first of the default categories is the “uncategorized”
358 category. It has the order `0` and then they increase by `100` per category.
359 This allows to put new categories between two already existing ones.
360
361 ```js
362 let categories = vimfx.get('categories')
363
364 // Add new category.
365 categories.custom = {
366 name: () => 'Custom commands',
367 order: 10000,
368 }
369
370 // Swap the order of the Location and Tabs categories.
371 ;[categories.location.order, categories.tabs.order] =
372 [categories.tabs.order, categories.location.order]
373 ```
374
375
376 ## Stability
377
378 The public API is currently **experimental** and therefore **unstable.** Things
379 might break with new VimFx versions.
380
381 As soon as VimFx 1.0.0 is released backwards compatibility will be a priority
382 and won’t be broken until VimFx 2.0.0.
Imprint / Impressum