]> git.gir.st - VimFx.git/blob - extension/lib/commands.coffee
Make scrolling commands scroll the focused element
[VimFx.git] / extension / lib / commands.coffee
1 ###
2 # Copyright Anton Khodakivskiy 2012, 2013, 2014.
3 # Copyright Simon Lydell 2013, 2014.
4 # Copyright Wang Zhuochun 2013, 2014.
5 #
6 # This file is part of VimFx.
7 #
8 # VimFx is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # VimFx is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with VimFx. If not, see <http://www.gnu.org/licenses/>.
20 ###
21
22 notation = require('vim-like-key-notation')
23 Command = require('./command')
24 { Marker } = require('./marker')
25 utils = require('./utils')
26 help = require('./help')
27 { getPref
28 , getFirefoxPref
29 , withFirefoxPrefAs } = require('./prefs')
30
31 { isProperLink, isTextInputElement, isContentEditable } = utils
32
33 { classes: Cc, interfaces: Ci, utils: Cu } = Components
34
35 XULDocument = Ci.nsIDOMXULDocument
36
37 # “Selecting an element” means “focusing and selecting the text, if any, of an
38 # element”.
39
40 # Select the Address Bar.
41 command_focus = (vim) ->
42 # This function works even if the Address Bar has been removed.
43 vim.rootWindow.focusAndSelectUrlBar()
44
45 # Select the Search Bar.
46 command_focus_search = (vim) ->
47 # The `.webSearch()` method opens a search engine in a tab if the Search Bar
48 # has been removed. Therefore we first check if it exists.
49 if vim.rootWindow.BrowserSearch.searchBar
50 vim.rootWindow.BrowserSearch.webSearch()
51
52 helper_paste = (vim) ->
53 url = vim.rootWindow.readFromClipboard()
54 postData = null
55 if not utils.isURL(url) and submission = utils.browserSearchSubmission(url)
56 url = submission.uri.spec
57 { postData } = submission
58 return {url, postData}
59
60 # Go to or search for the contents of the system clipboard.
61 command_paste = (vim) ->
62 { url, postData } = helper_paste(vim)
63 vim.rootWindow.gBrowser.loadURIWithFlags(url, null, null, null, postData)
64
65 # Go to or search for the contents of the system clipboard in a new tab.
66 command_paste_tab = (vim) ->
67 { url, postData } = helper_paste(vim)
68 vim.rootWindow.gBrowser.selectedTab =
69 vim.rootWindow.gBrowser.addTab(url, null, null, postData, null, false)
70
71 # Copy the current URL to the system clipboard.
72 command_yank = (vim) ->
73 utils.writeToClipboard(vim.window.location.href)
74
75 # Reload the current tab, possibly from cache.
76 command_reload = (vim) ->
77 vim.rootWindow.BrowserReload()
78
79 # Reload the current tab, skipping cache.
80 command_reload_force = (vim) ->
81 vim.rootWindow.BrowserReloadSkipCache()
82
83 # Reload all tabs, possibly from cache.
84 command_reload_all = (vim) ->
85 vim.rootWindow.gBrowser.reloadAllTabs()
86
87 # Reload all tabs, skipping cache.
88 command_reload_all_force = (vim) ->
89 for tab in vim.rootWindow.gBrowser.visibleTabs
90 window = tab.linkedBrowser.contentWindow
91 window.location.reload(true)
92
93 # Stop loading the current tab.
94 command_stop = (vim) ->
95 vim.window.stop()
96
97 # Stop loading all tabs.
98 command_stop_all = (vim) ->
99 for tab in vim.rootWindow.gBrowser.visibleTabs
100 window = tab.linkedBrowser.contentWindow
101 window.stop()
102
103 axisMap =
104 x: ['left', 'clientWidth', 'horizontalScrollDistance', 5]
105 y: ['top', 'clientHeight', 'verticalScrollDistance', 20]
106 helper_scroll = (method, type, axis, amount, vim, event, count = 1) ->
107 frameDocument = event.target.ownerDocument
108 element =
109 if vim.state.scrollableElements.has(event.target)
110 event.target
111 else
112 frameDocument.documentElement
113
114 [ direction, dimension, distance, lineAmount ] = axisMap[axis]
115
116 if method == 'scrollTo'
117 amount = Math.min(amount, element.scrollTopMax)
118 else
119 unit = switch type
120 when 'lines'
121 getFirefoxPref("toolkit.scrollbox.#{ distance }") * lineAmount
122 when 'pages'
123 element[dimension]
124 amount *= unit * count
125
126 options = {}
127 options[direction] = amount
128 if getFirefoxPref('general.smoothScroll') and
129 getFirefoxPref("general.smoothScroll.#{ type }")
130 options.behavior = 'smooth'
131
132 withFirefoxPrefAs(
133 'layout.css.scroll-behavior.spring-constant',
134 getPref("smoothScroll.#{ type }.spring-constant"),
135 ->
136 element[method](options)
137 # When scrolling the whole page, the body sometimes needs to be scrolled
138 # too.
139 if element == frameDocument.documentElement
140 frameDocument.body?[method](options)
141 )
142
143 command_scroll_to_top =
144 helper_scroll.bind(undefined, 'scrollTo', 'other', 'y', 0)
145 command_scroll_to_bottom =
146 helper_scroll.bind(undefined, 'scrollTo', 'other', 'y', Infinity)
147 command_scroll_down =
148 helper_scroll.bind(undefined, 'scrollBy', 'lines', 'y', +1)
149 command_scroll_up =
150 helper_scroll.bind(undefined, 'scrollBy', 'lines', 'y', -1)
151 command_scroll_right =
152 helper_scroll.bind(undefined, 'scrollBy', 'lines', 'x', +1)
153 command_scroll_left =
154 helper_scroll.bind(undefined, 'scrollBy', 'lines', 'x', -1)
155 command_scroll_half_page_down =
156 helper_scroll.bind(undefined, 'scrollBy', 'pages', 'y', +0.5)
157 command_scroll_half_page_up =
158 helper_scroll.bind(undefined, 'scrollBy', 'pages', 'y', -0.5)
159 command_scroll_page_down =
160 helper_scroll.bind(undefined, 'scrollBy', 'pages', 'y', +1)
161 command_scroll_page_up =
162 helper_scroll.bind(undefined, 'scrollBy', 'pages', 'y', -1)
163
164 # Open a new tab and select the Address Bar.
165 command_open_tab = (vim) ->
166 vim.rootWindow.BrowserOpenTab()
167
168 absoluteTabIndex = (relativeIndex, gBrowser) ->
169 tabs = gBrowser.visibleTabs
170 { selectedTab } = gBrowser
171
172 currentIndex = tabs.indexOf(selectedTab)
173 absoluteIndex = currentIndex + relativeIndex
174 numTabs = tabs.length
175
176 wrap = (Math.abs(relativeIndex) == 1)
177 if wrap
178 absoluteIndex %%= numTabs
179 else
180 absoluteIndex = Math.max(0, absoluteIndex)
181 absoluteIndex = Math.min(absoluteIndex, numTabs - 1)
182
183 return absoluteIndex
184
185 helper_switch_tab = (direction, vim, event, count = 1) ->
186 { gBrowser } = vim.rootWindow
187 gBrowser.selectTabAtIndex(absoluteTabIndex(direction * count, gBrowser))
188
189 # Switch to the previous tab.
190 command_tab_prev = helper_switch_tab.bind(undefined, -1)
191
192 # Switch to the next tab.
193 command_tab_next = helper_switch_tab.bind(undefined, +1)
194
195 helper_move_tab = (direction, vim, event, count = 1) ->
196 { gBrowser } = vim.rootWindow
197 { selectedTab } = gBrowser
198 { pinned } = selectedTab
199
200 index = absoluteTabIndex(direction * count, gBrowser)
201
202 if index < gBrowser._numPinnedTabs
203 gBrowser.pinTab(selectedTab) unless pinned
204 else
205 gBrowser.unpinTab(selectedTab) if pinned
206
207 gBrowser.moveTabTo(selectedTab, index)
208
209 # Move the current tab backward.
210 command_tab_move_left = helper_move_tab.bind(undefined, -1)
211
212 # Move the current tab forward.
213 command_tab_move_right = helper_move_tab.bind(undefined, +1)
214
215 # Load the home page.
216 command_home = (vim) ->
217 vim.rootWindow.BrowserHome()
218
219 # Switch to the first tab.
220 command_tab_first = (vim) ->
221 vim.rootWindow.gBrowser.selectTabAtIndex(0)
222
223 # Switch to the first non-pinned tab.
224 command_tab_first_non_pinned = (vim) ->
225 firstNonPinned = vim.rootWindow.gBrowser._numPinnedTabs
226 vim.rootWindow.gBrowser.selectTabAtIndex(firstNonPinned)
227
228 # Switch to the last tab.
229 command_tab_last = (vim) ->
230 vim.rootWindow.gBrowser.selectTabAtIndex(-1)
231
232 # Toggle Pin Tab.
233 command_toggle_pin_tab = (vim) ->
234 currentTab = vim.rootWindow.gBrowser.selectedTab
235
236 if currentTab.pinned
237 vim.rootWindow.gBrowser.unpinTab(currentTab)
238 else
239 vim.rootWindow.gBrowser.pinTab(currentTab)
240
241 # Duplicate current tab.
242 command_duplicate_tab = (vim) ->
243 { gBrowser } = vim.rootWindow
244 gBrowser.duplicateTab(gBrowser.selectedTab)
245
246 # Close all tabs from current to the end.
247 command_close_tabs_to_end = (vim) ->
248 { gBrowser } = vim.rootWindow
249 gBrowser.removeTabsToTheEndFrom(gBrowser.selectedTab)
250
251 # Close all tabs except the current.
252 command_close_other_tabs = (vim) ->
253 { gBrowser } = vim.rootWindow
254 gBrowser.removeAllTabsBut(gBrowser.selectedTab)
255
256 # Close current tab.
257 command_close_tab = (vim, event, count = 1) ->
258 { gBrowser } = vim.rootWindow
259 return if gBrowser.selectedTab.pinned
260 currentIndex = gBrowser.visibleTabs.indexOf(gBrowser.selectedTab)
261 for tab in gBrowser.visibleTabs[currentIndex...(currentIndex + count)]
262 gBrowser.removeTab(tab)
263
264 # Restore last closed tab.
265 command_restore_tab = (vim, event, count = 1) ->
266 vim.rootWindow.undoCloseTab() for [1..count]
267
268 # Combine links with the same href.
269 combine = (hrefs, marker) ->
270 if marker.type == 'link'
271 { href } = marker.element
272 if href of hrefs
273 parent = hrefs[href]
274 marker.parent = parent
275 parent.weight += marker.weight
276 parent.numChildren++
277 else
278 hrefs[href] = marker
279 return marker
280
281 # Follow links, focus text inputs and click buttons with hint markers.
282 command_follow = (vim, event, count = 1) ->
283 hrefs = {}
284 filter = (element, getElementShape) ->
285 document = element.ownerDocument
286 isXUL = (document instanceof XULDocument)
287 semantic = true
288 switch
289 when isProperLink(element)
290 type = 'link'
291 when isTextInputElement(element) or isContentEditable(element)
292 type = 'text'
293 when element.tabIndex > -1 and
294 not (isXUL and element.nodeName.endsWith('box'))
295 type = 'clickable'
296 unless isXUL or element.nodeName in ['A', 'INPUT', 'BUTTON']
297 semantic = false
298 when element != document.documentElement and
299 vim.state.scrollableElements.has(element)
300 type = 'scrollable'
301 when element.hasAttribute('onclick') or
302 element.hasAttribute('onmousedown') or
303 element.hasAttribute('onmouseup') or
304 element.hasAttribute('oncommand') or
305 element.getAttribute('role') in ['link', 'button'] or
306 # Twitter special-case.
307 element.classList.contains('js-new-tweets-bar') or
308 # Feedly special-case.
309 element.hasAttribute('data-app-action') or
310 element.hasAttribute('data-uri') or
311 element.hasAttribute('data-page-action')
312 type = 'clickable'
313 semantic = false
314 # Putting markers on `<label>` elements is generally redundant, because
315 # its `<input>` gets one. However, some sites hide the actual `<input>`
316 # but keeps the `<label>` to click, either for styling purposes or to keep
317 # the `<input>` hidden until it is used. In those cases we should add a
318 # marker for the `<label>`.
319 when element.nodeName == 'LABEL'
320 if element.htmlFor
321 input = document.getElementById(element.htmlFor)
322 if input and not getElementShape(input)
323 type = 'clickable'
324 # Elements that have “button” somewhere in the class might be clickable,
325 # unless they contain a real link or button or yet an element with
326 # “button” somewhere in the class, in which case they likely are
327 # “button-wrapper”s. (`<SVG element>.className` is not a string!)
328 when not isXUL and typeof element.className == 'string' and
329 element.className.toLowerCase().contains('button')
330 unless element.querySelector('a, button, [class*=button]')
331 type = 'clickable'
332 semantic = false
333 # When viewing an image it should get a marker to toggle zoom.
334 when document.body?.childElementCount == 1 and
335 element.nodeName == 'IMG' and
336 (element.classList.contains('overflowing') or
337 element.classList.contains('shrinkToFit'))
338 type = 'clickable'
339 return unless type
340 return unless shape = getElementShape(element)
341 return combine(hrefs, new Marker(element, shape, {semantic, type}))
342
343 callback = (marker) ->
344 { element } = marker
345 element.focus()
346 last = (count == 1)
347 if not last and marker.type == 'link'
348 utils.openTab(vim.rootWindow, element.href, {
349 inBackground: true
350 relatedToCurrent: true
351 })
352 else
353 if element.target == '_blank'
354 targetReset = element.target
355 element.target = ''
356 utils.simulateClick(element)
357 element.target = targetReset if targetReset
358 count--
359 return (not last and marker.type != 'text')
360
361 vim.enterMode('hints', filter, callback)
362
363 # Like command_follow but multiple times.
364 command_follow_multiple = (vim, event) ->
365 command_follow(vim, event, Infinity)
366
367 # Follow links in a new background tab with hint markers.
368 command_follow_in_tab = (vim, event, count = 1, inBackground = true) ->
369 hrefs = {}
370 filter = (element, getElementShape) ->
371 return unless isProperLink(element)
372 return unless shape = getElementShape(element)
373 return combine(hrefs, new Marker(element, shape, {semantic: true}))
374
375 callback = (marker) ->
376 last = (count == 1)
377 utils.openTab(vim.rootWindow, marker.element.href, {
378 inBackground: if last then inBackground else true
379 relatedToCurrent: true
380 })
381 count--
382 return not last
383
384 vim.enterMode('hints', filter, callback)
385
386 # Follow links in a new foreground tab with hint markers.
387 command_follow_in_focused_tab = (vim, event, count = 1) ->
388 command_follow_in_tab(vim, event, count, false)
389
390 # Copy the URL or text of a markable element to the system clipboard.
391 command_marker_yank = (vim) ->
392 hrefs = {}
393 filter = (element, getElementShape) ->
394 type = switch
395 when isProperLink(element) then 'link'
396 when isTextInputElement(element) then 'textInput'
397 when isContentEditable(element) then 'contenteditable'
398 return unless type
399 return unless shape = getElementShape(element)
400 return combine(hrefs, new Marker(element, shape, {semantic: true, type}))
401
402 callback = (marker) ->
403 { element } = marker
404 text = switch marker.type
405 when 'link' then element.href
406 when 'textInput' then element.value
407 when 'contenteditable' then element.textContent
408 utils.writeToClipboard(text)
409
410 vim.enterMode('hints', filter, callback)
411
412 # Focus element with hint markers.
413 command_marker_focus = (vim) ->
414 filter = (element, getElementShape) ->
415 type = switch
416 when element.tabIndex > -1
417 'focusable'
418 when element != element.ownerDocument.documentElement and
419 vim.state.scrollableElements.has(element)
420 'scrollable'
421 return unless type
422 return unless shape = getElementShape(element)
423 return new Marker(element, shape, {semantic: true, type})
424
425 callback = (marker) ->
426 { element } = marker
427 element.focus()
428 element.select?()
429
430 vim.enterMode('hints', filter, callback)
431
432 # Search for the prev/next patterns in the following attributes of the element.
433 # `rel` should be kept as the first attribute, since the standard way of marking
434 # up prev/next links (`rel="prev"` and `rel="next"`) should be favored. Even
435 # though some of these attributes only allow a fixed set of keywords, we
436 # pattern-match them anyways since lots of sites don’t follow the spec and use
437 # the attributes arbitrarily.
438 attrs = ['rel', 'role', 'data-tooltip', 'aria-label']
439 helper_follow_pattern = (type, vim) ->
440 { document } = vim.window
441
442 # If there’s a `<link rel=prev/next>` element we use that.
443 for link in document.head.getElementsByTagName('link')
444 # Also support `rel=previous`, just like Google.
445 if type == link.rel.toLowerCase().replace(/^previous$/, 'prev')
446 vim.rootWindow.gBrowser.loadURI(link.href)
447 return
448
449 # Otherwise we look for a link or button on the page that seems to go to the
450 # previous or next page.
451 candidates = document.querySelectorAll('a, button')
452 patterns = utils.splitListString(getPref("#{ type }_patterns"))
453 if matchingLink = utils.getBestPatternMatch(patterns, attrs, candidates)
454 utils.simulateClick(matchingLink)
455
456 # Follow previous page.
457 command_follow_prev = helper_follow_pattern.bind(undefined, 'prev')
458
459 # Follow next page.
460 command_follow_next = helper_follow_pattern.bind(undefined, 'next')
461
462 # Focus last focused or first text input and enter text input mode.
463 command_text_input = (vim, event, count) ->
464 console.log count
465 { lastFocusedTextInput } = vim.state
466 inputs = Array.filter(
467 vim.window.document.querySelectorAll('input, textarea'), (element) ->
468 return utils.isTextInputElement(element) and utils.area(element) > 0
469 )
470 if lastFocusedTextInput and lastFocusedTextInput not in inputs
471 inputs.push(lastFocusedTextInput)
472 return unless inputs.length > 0
473 inputs.sort((a, b) -> a.tabIndex - b.tabIndex)
474 if count == null and lastFocusedTextInput
475 count = inputs.indexOf(lastFocusedTextInput) + 1
476 inputs[count - 1].select()
477 vim.enterMode('text-input', inputs)
478
479 # Go up one level in the URL hierarchy.
480 command_go_up_path = (vim, event, count = 1) ->
481 { pathname } = vim.window.location
482 vim.window.location.pathname = pathname.replace(
483 /// (?: /[^/]+ ){1,#{ count }} /?$ ///, ''
484 )
485
486 # Go up to root of the URL hierarchy.
487 command_go_to_root = (vim) ->
488 vim.window.location.href = vim.window.location.origin
489
490 helper_go_history = (num, vim, event, count = 1) ->
491 { index } = vim.rootWindow.getWebNavigation().sessionHistory
492 { history } = vim.window
493 num *= count
494 num = Math.max(num, -index)
495 num = Math.min(num, history.length - 1 - index)
496 return if num == 0
497 history.go(num)
498
499 # Go back in history.
500 command_back = helper_go_history.bind(undefined, -1)
501
502 # Go forward in history.
503 command_forward = helper_go_history.bind(undefined, +1)
504
505 findStorage = {lastSearchString: ''}
506
507 helper_find = (highlight, vim) ->
508 findBar = vim.rootWindow.gBrowser.getFindBar()
509
510 findBar.onFindCommand()
511 findBar._findField.focus()
512 findBar._findField.select()
513
514 return unless highlightButton = findBar.getElement('highlight')
515 if highlightButton.checked != highlight
516 highlightButton.click()
517
518 # Open the find bar, making sure that hightlighting is off.
519 command_find = helper_find.bind(undefined, false)
520
521 # Open the find bar, making sure that hightlighting is on.
522 command_find_hl = helper_find.bind(undefined, true)
523
524 helper_find_again = (direction, vim) ->
525 findBar = vim.rootWindow.gBrowser.getFindBar()
526 if findStorage.lastSearchString.length > 0
527 findBar._findField.value = findStorage.lastSearchString
528 findBar.onFindAgainCommand(direction)
529
530 # Search for the last pattern.
531 command_find_next = helper_find_again.bind(undefined, false)
532
533 # Search for the last pattern backwards.
534 command_find_prev = helper_find_again.bind(undefined, true)
535
536 # Enter insert mode.
537 command_insert_mode = (vim) ->
538 vim.enterMode('insert')
539
540 # Quote next keypress (pass it through to the page).
541 command_quote = (vim, event, count = 1) ->
542 vim.enterMode('insert', count)
543
544 # Display the Help Dialog.
545 command_help = (vim) ->
546 help.injectHelp(vim.window.document, require('./modes'))
547
548 # Open and select the Developer Toolbar.
549 command_dev = (vim) ->
550 vim.rootWindow.DeveloperToolbar.show(true) # focus
551
552 command_Esc = (vim, event) ->
553 utils.blurActiveElement(vim.window)
554
555 # Blur active XUL control.
556 callback = -> event.originalTarget?.ownerDocument?.activeElement?.blur()
557 vim.window.setTimeout(callback, 0)
558
559 help.removeHelp(vim.window.document)
560
561 vim.rootWindow.DeveloperToolbar.hide()
562
563 vim.rootWindow.gBrowser.getFindBar().close()
564
565 vim.rootWindow.TabView.hide()
566
567 { document } = vim.window
568 if document.exitFullscreen
569 document.exitFullscreen()
570 else
571 document.mozCancelFullScreen()
572
573
574 # coffeelint: disable=max_line_length
575 commands = [
576 new Command('urls', 'focus', command_focus, [['o']])
577 new Command('urls', 'focus_search', command_focus_search, [['O']])
578 new Command('urls', 'paste', command_paste, [['p']])
579 new Command('urls', 'paste_tab', command_paste_tab, [['P']])
580 new Command('urls', 'marker_yank', command_marker_yank, [['y', 'f']])
581 new Command('urls', 'marker_focus', command_marker_focus, [['v', 'f']])
582 new Command('urls', 'yank', command_yank, [['y', 'y']])
583 new Command('urls', 'reload', command_reload, [['r']])
584 new Command('urls', 'reload_force', command_reload_force, [['R']])
585 new Command('urls', 'reload_all', command_reload_all, [['a', 'r']])
586 new Command('urls', 'reload_all_force', command_reload_all_force, [['a', 'R']])
587 new Command('urls', 'stop', command_stop, [['s']])
588 new Command('urls', 'stop_all', command_stop_all, [['a', 's']])
589
590 new Command('nav', 'scroll_to_top', command_scroll_to_top , [['g', 'g']])
591 new Command('nav', 'scroll_to_bottom', command_scroll_to_bottom, [['G']])
592 new Command('nav', 'scroll_down', command_scroll_down, [['j']])
593 new Command('nav', 'scroll_up', command_scroll_up, [['k']])
594 new Command('nav', 'scroll_left', command_scroll_left, [['h']])
595 new Command('nav', 'scroll_right', command_scroll_right , [['l']])
596 new Command('nav', 'scroll_half_page_down', command_scroll_half_page_down, [['d']])
597 new Command('nav', 'scroll_half_page_up', command_scroll_half_page_up, [['u']])
598 new Command('nav', 'scroll_page_down', command_scroll_page_down, [['<space>']])
599 new Command('nav', 'scroll_page_up', command_scroll_page_up, [['<s-space>']])
600
601 new Command('tabs', 'open_tab', command_open_tab, [['t']])
602 new Command('tabs', 'tab_prev', command_tab_prev, [['J'], ['g', 'T']])
603 new Command('tabs', 'tab_next', command_tab_next, [['K'], ['g', 't']])
604 new Command('tabs', 'tab_move_left', command_tab_move_left, [['g', 'J']])
605 new Command('tabs', 'tab_move_right', command_tab_move_right, [['g', 'K']])
606 new Command('tabs', 'home', command_home, [['g', 'h']])
607 new Command('tabs', 'tab_first', command_tab_first, [['g', 'H'], ['g', '0']])
608 new Command('tabs', 'tab_first_non_pinned', command_tab_first_non_pinned, [['g', '^']])
609 new Command('tabs', 'tab_last', command_tab_last, [['g', 'L'], ['g', '$']])
610 new Command('tabs', 'toggle_pin_tab', command_toggle_pin_tab, [['g', 'p']])
611 new Command('tabs', 'duplicate_tab', command_duplicate_tab, [['y', 't']])
612 new Command('tabs', 'close_tabs_to_end', command_close_tabs_to_end, [['g', 'x', '$']])
613 new Command('tabs', 'close_other_tabs', command_close_other_tabs, [['g', 'x', 'a']])
614 new Command('tabs', 'close_tab', command_close_tab, [['x']])
615 new Command('tabs', 'restore_tab', command_restore_tab, [['X']])
616
617 new Command('browse', 'follow', command_follow, [['f']])
618 new Command('browse', 'follow_in_tab', command_follow_in_tab, [['F']])
619 new Command('browse', 'follow_in_focused_tab', command_follow_in_focused_tab, [['g', 'f']])
620 new Command('browse', 'follow_multiple', command_follow_multiple, [['a', 'f']])
621 new Command('browse', 'follow_previous', command_follow_prev, [['[']])
622 new Command('browse', 'follow_next', command_follow_next, [[']']])
623 new Command('browse', 'text_input', command_text_input, [['g', 'i']])
624 new Command('browse', 'go_up_path', command_go_up_path, [['g', 'u']])
625 new Command('browse', 'go_to_root', command_go_to_root, [['g', 'U']])
626 new Command('browse', 'back', command_back, [['H']])
627 new Command('browse', 'forward', command_forward, [['L']])
628
629 new Command('misc', 'find', command_find, [['/']])
630 new Command('misc', 'find_hl', command_find_hl, [['a', '/']])
631 new Command('misc', 'find_next', command_find_next, [['n']])
632 new Command('misc', 'find_prev', command_find_prev, [['N']])
633 new Command('misc', 'insert_mode', command_insert_mode, [['i']])
634 new Command('misc', 'quote', command_quote, [['I']])
635 new Command('misc', 'help', command_help, [['?']])
636 new Command('misc', 'dev', command_dev, [[':']])
637
638 escapeCommand =
639 new Command('misc', 'Esc', command_Esc, [['<escape>']])
640 ]
641 # coffeelint: enable=max_line_length
642
643 exports.commands = commands
644 exports.escapeCommand = escapeCommand
645 exports.findStorage = findStorage
Imprint / Impressum