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