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