Control Firefox to Scroll/Refresh/Close from Emacs

It’s very common for me to program while read documents in a web browser, and I think it’s annoying to switch between the browser and the text editor constantly.

Here I have a few Elisp functions defined, which allow me to control Firefox to scroll, close tabs and so on.

1 Usage

description function name keybinding
refresh current tab moz-reload-browser C-c m g
scroll down moz-page-down C-c m n
scroll up moz-page-up C-c m p
close current tab moz-tab-close C-c m k

2 Elisp Code and Firefox Plugin

Put the following code in your init.el:

(defun moz-send-command (command)
  "Send COMMAND to *MozRepl* process.

  If the process doesn't exist, create one."
  (comint-send-string (inferior-moz-process) command))

(defun moz-reload-browser ()
  "Refresh current page"
  (interactive)
  (moz-send-command
   "setTimeout(function(){content.document.location.reload(true);}, '500');")
  )

(defun moz-page-down ()
  "Scroll down the current window by one page."
  (interactive)
  (moz-send-command "content.window.scrollByPages(1);")
  )

(defun moz-page-up ()
  "Scroll up the current window by one page."
  (interactive)
  (moz-send-command "content.window.scrollByPages(-1);")
  )

(defun moz-tab-close ()
  "Close current tab"
  (interactive)
  (moz-send-command "content.window.close();")
  )

(global-set-key (kbd "C-c m g") 'moz-reload-browser)
(global-set-key (kbd "C-c m n") 'moz-page-down)
(global-set-key (kbd "C-c m p") 'moz-page-up)
(global-set-key (kbd "C-c m k") 'moz-tab-close)

Then:

  • Install moz-repl in Emacs (I get it installed by executing M-x el-get install moz-repl)
  • Install MozRepl plugin in Firefox

3 Hack Log

Reading Caching with Rails and coding some Rails app, keep switching between Emacs and Firefox. Annoying, can’t I control Firefox from Emacs?

I’ve seen Elisp functions for refreshing Firefox without leaving Emacs and I know it makes use of mozrepl.

(defun moz-reload-browser ()
  (interactive)
  (comint-send-string
   (inferior-moz-process)
   "setTimeout(function(){content.document.location.reload(true);}, '500');"))

If actions such as scrolling up and down could also be done through mozrepl, then the functions I want would be very easy to write. Switch to Firefox, search in duckduckgo with keywords “firefox console scroll down this page”. From the results, I get a feeling that it should be something like window.scrollxxx.

Press F12 to open Firebug, switch to the console, type in “window.scroll” and see what are available from the completion candidates. scrollByPages looks really suspicious.

Give it a go, type in “window.scrollByPages” in the console, it returns: scrollByPages()

Hmm, pass in an argument and try again: scrollByPages(1), it scrolls down, nice!

Try a negative argument: scrollByPages(-1), it scrolls up as expected.

Now, it’s time to write functions:

(defun moz-page-down ()
  "Scroll down the current window by one page."
  (interactive)
  (comint-send-string
   (inferior-moz-process)
   "content.window.scrollByPages(1);")
  )

It doesn’t work. Type in window.scrollByPages(1); in the Emacs MozRepl buffer and execute, doesn’t work neither.

Find another related function in my own init.el:

(defun moz-update (&rest ignored)
  "Update the remote mozrepl instance"
  (interactive)
  (comint-send-string (inferior-moz-process)
                      (concat "content.document.body.innerHTML="
                              (json-encode (buffer-string)) ";")))

It gets document via content.document. Let me try this, type in content.window.scrollByPages(1); in MozRepl and press enter, it works.

Rewrite my function:

(defun moz-page-down ()
  "Scroll down the current window by one page."
  (interactive)
  (comint-send-string
   (inferior-moz-process)
   "content.window.scrollByPages(1);")
  )

Try again, works like a charm!

Write a function to scroll up:

(defun moz-page-up ()
  "Scroll up the current window by one page."
  (interactive)
  (comint-send-string
   (inferior-moz-process)
   "content.window.scrollByPages(-1);")
  )

Bind keyboard shortcuts to those functions:

(global-set-key (kbd "C-c m n") 'moz-page-down)
(global-set-key (kbd "C-c m p") 'moz-page-up)

Write a function for closing the current tab:

(defun moz-tab-close ()
  "Close current tab"
  (interactive)
  (comint-send-string
   (inferior-moz-process)
   "content.window.close();")
  )
(global-set-key (kbd "C-c m k") 'moz-tab-close)

I’m repeating myself, which is said to be bad. Let me clean them up a bit:

(defun moz-send-command (command)
  "Send COMMAND to *MozRepl* process.

If the process doesn't exist, create one."
  (comint-send-string (inferior-moz-process) command))

(defun moz-reload-browser ()
  "Refresh current page"
  (interactive)
  (moz-send-command
   "setTimeout(function(){content.document.location.reload(true);}, '500');")
  )

(defun moz-page-down ()
  "Scroll down the current window by one page."
  (interactive)
  (moz-send-command "content.window.scrollByPages(1);")
  )

(defun moz-page-up ()
  "Scroll up the current window by one page."
  (interactive)
  (moz-send-command "content.window.scrollByPages(-1);")
  )

(defun moz-tab-close ()
  "Close current tab"
  (interactive)
  (moz-send-command "content.window.close();")
  )

Done!