Skip to content
Simon Lydell edited this page Sep 10, 2016 · 52 revisions

Please share useful custom commands here!

See documentation/config-file.md for how to use this.

Tip: Here’s a way to find how many built-in Firefox commands are implemented:

  1. Go to about:config and make sure that devtools.chrome.enabled is set to true.

  2. Open the browser console.

  3. Run the following code:

    Array.map(document.querySelectorAll('command'), command => `${command.id}: ${command.getAttribute('oncommand')}`).join('\n')

    That prints a list of command names and the code they use.

Open new tab and focus Search Bar

let {commands} = vimfx.modes.normal
vimfx.addCommand({
  name: 'tab_new_and_focus_search_bar',
  description: 'Open new tab and focus Search Bar',
  category: 'tabs',
  order: commands.tab_new.order + 1,
}, args => {
  commands.tab_new.run(args)
  commands.focus_search_bar.run(args)
})

Zoom

vimfx.addCommand({
  name: 'zoom_in',
  description: 'Zoom in',
}, ({vim}) => {
  vim.window.FullZoom.enlarge()
})

You can also replace enlarge with reduce to zoom out, and with reset to reset to 100%.

Bookmark page

vimfx.addCommand({
  name: 'bookmark_page',
  description: 'Bookmark page',
}, ({vim}) => {
  let {window} = vim
  window.PlacesCommandHook.bookmarkCurrentPage(true, window.PlacesUtils.bookmarksMenuFolderId)
})

The above is equivalent to the Firefox default shortcut <c-d>.

Search bookmarks

let {commands} = vimfx.modes.normal
vimfx.addCommand({
  name: 'search_bookmarks',
  description: 'Search bookmarks',
  category: 'location',
  order: commands.focus_location_bar.order + 1,
}, (args) => {
  commands.focus_location_bar.run(args)
  args.vim.window.gURLBar.value = '* '
})

You may also want to read more about handy location bar features.

Open a specific URL

vimfx.addCommand({
  name: 'goto_downloads',
  description: 'Downloads',
}, ({vim}) => {
  vim.window.gBrowser.loadURI('about:downloads')
})

Replace loadURI with loadOneTab to open in a new tab instead.

Here are some URLs you might find interesting (they should be self-explanatory):

  • about:downloads
  • about:preferences
  • about:addons

Like about: pages? Go to about:about to list them all!

Search for the selected text

vimfx.addCommand({
  name: 'search_selected_text',
  description: 'Search for the selected text'
}, ({vim}) => {
  let {messageManager} = vim.window.gBrowser.selectedBrowser
  let callback = ({data: {selection}}) => {
  vimfx.send(vim, 'getSelection', null, selection => {
    let inTab = true // Change to `false` if you’d like to search in current tab.
    vim.window.BrowserSearch.loadSearch(selection, inTab)
  })
})

frame.js:

vimfx.listen('getSelection', (data, callback) => {
  let selection = content.getSelection().toString()
  callback(selection)
})

Web console

vimfx.addCommand({
  name: 'web_console',
  description: 'Web console',
}, ({vim}) => {
  vim.window.gDevToolsBrowser.selectToolCommand(vim.window.gBrowser, 'webconsole')
})

The above is equivalent to the Firefox default shortcut <c-K>. Alternatively, you can use the following to toggle the developer tools instead:

vim.window.gDevToolsBrowser.toggleToolboxCommand(vim.window.gBrowser)

Move tab to index

This command moves the current tab before tab number count.

vimfx.addCommand({
  name: 'tab_move_to_index',
  description: 'Move tab to index',
  category: 'tabs',
  order: commands.tab_move_forward.order + 1,
}, ({vim, count}) => {
  if (count === undefined) {
    vim.notify('Provide a count')
    return
  }
  let {window} = vim
  window.setTimeout(() => {
    let {selectedTab} = window.gBrowser
    if (selectedTab.pinned) {
      vim.notify('Run from a non-pinned tab')
      return
    }
    let newPosition = window.gBrowser._numPinnedTabs + count - 1
    window.gBrowser.moveTabTo(selectedTab, newPosition)
  }, 0)
})

Tip: Add the following to custom styling to make it easier to work out which number to type. It turns the tab close buttons into numbers until you hover the tab:

#TabsToolbar {
  counter-reset: tabs-counter;
}

.tab-close-button:not([pinned]) {
  visibility: hidden;
  display: block;
  color: inherit;
  counter-increment: tabs-counter;

  &::before {
    content: counter(tabs-counter);
    visibility: visible;
    font-weight: normal;
    font-style: normal;
  }
}

Close tabs to the left

let {commands} = vimfx.modes.normal
vimfx.addCommand({
  name: 'tab_close_to_start',
  description: 'Close tabs to the left',
  category: 'tabs',
  order: commands.tab_close_to_end.order + 1,
}, ({vim}) => {
  let {gBrowser} = vim.window
  Array.slice(gBrowser.tabs, gBrowser._numPinnedTabs, gBrowser.selectedTab._tPos)
    .forEach(tab => gBrowser.removeTab(tab))
})

Click the NoScript button

vimfx.addCommand({
  name: 'noscript_click_toolbar_button',
  description: 'NoScript',
}, ({vim}) => {
  vim.window.document.getElementById('noscript-tbb').click()
})

Play a link with an external media player

const {classes: Cc, interfaces: Ci} = Components

const mpv_path = '/usr/bin/mpv'
const mpv_options = '--video-unscaled=yes --ytdl-raw-options=format=best'

vimfx.addCommand({
  name: 'play_with_mpv',
  description: 'Play the focused link with MPV'
}, ({vim}) => {
  vimfx.send(vim, 'getCurrentHref', null, url => {
    let file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile)
    file.initWithPath(mpv_path)

    let process = Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess)
    process.init(file)

    let args = mpv_options.split(' ')

    if (url.includes('youtube.com')) {
      // Parse url params to an object like:
      // {"v":"g04s2u30NfQ","index":"3","list":"PL58H4uS5fMRzmMC_SfMelnCoHgB8COa5r"}
      let qs = (function(a) {
        if (a == '') return {}
        let b = {}
        for (let i = 0; i < a.length; ++i) {
          let p = a[i].split('=', 2)
          if (p.length == 1) {
            b[p[0]] = ''
          } else {
            b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, ' '))
          }
        }
        return b
      })(url.substr(1).split('&'))

      if (qs['list'] && qs['index']) {
        // Example args: ['--video-unscaled=yes', '--ytdl-raw-options=format=best']
        // So check for ytdl-raw-options.
        let ytdlRawOptionsIndex = -1
        for (let i = 0; i < args.length; i++) {
          if (args[i].includes('ytdl-raw-options')) {
            ytdlRawOptionsIndex = i
            break
          }
        }

        if (ytdlRawOptionsIndex > -1) {
            args[ytdlRawOptionsIndex] += `,yes-playlist=,playlist-start=${qs['index']}`
        } else {
            args.push(`--ytdl-raw-options=yes-playlist=,playlist-start=${qs['index']}`)
        }
      }
    }

    args.push(url)

    // process.run(false, args, args.length)
    process.runAsync(args, args.length)
  })
})

frame.js:

vimfx.listen('getCurrentHref', (data, callback) => {
  let {href} = content.document.activeElement
  callback(href)
})

Sorry for hairy code :)

Clone this wiki locally