Emacs w3m: Open pages in external browsers

Sometimes w3m is not enough. To make it easier to open the current page in a browser such as Mozilla Firefox, add the following to your ~/.emacs:

(defun wicked/w3m-open-current-page-in-firefox ()
  "Open the current URL in Mozilla Firefox."
  (interactive)
  (browse-url-firefox w3m-current-url)) ;; (1)

(defun wicked/w3m-open-link-or-image-in-firefox ()
  "Open the current link or image in Firefox."
  (interactive)
  (browse-url-firefox (or (w3m-anchor) ;; (2)
                          (w3m-image)))) ;; (3)

This defines a function that uses the current URL being browsed(1) and another function that takes the URL of the link at point(2). If no link is found, it takes the URL of the image at point(3).

You can use other browse-url functions instead of browse-url-firefox. For example, replacing browse-url-firefox with browse-url-kde will open the page, link, or image in Konqueror, KDE’s web browser.

I like binding f to the function that opens the current URL in Mozilla Firefox and F to the function that opens the current link or image in Mozilla Firefox. To do the same, add the following to your ~/.emacs:

(eval-after-load 'w3m
  (progn 
    (define-key w3m-mode-map "f" 'wicked/w3m-open-current-page-in-firefox)
    (define-key w3m-mode-map "F" 'wicked/w3m-open-link-or-image-in-firefox)))


This is part of the book that I’m writing about Emacs, which will be published by No Starch Press if I manage to get it together in time.

Emacs and w3m: Making tabbed browsing easier

If you browse with a lot of open tabs, like I do, w3m will be much easier to use once you remap w3m-next-buffer and w3m-previous-buffer onto single-key shortcuts, allowing you to press a key to quickly flip between tabs.

By default, w3m-previous-buffer is mapped to C-c C-p and w3m-next-buffer is mapped to C-c C-n. On a QWERTY keyboard, you may want to remap w3m-previous-buffer to q and w3m-next-buffer to w. You’ll probably also want to remap w3m-close-window (which had been bound to q), and x is a good keybinding for that. To make all these changes, add the following to your ~/.emacs:

(eval-after-load 'w3m
  '(progn
     (define-key w3m-mode-map "q" 'w3m-previous-buffer)
     (define-key w3m-mode-map "w" 'w3m-next-buffer)
     (define-key w3m-mode-map "x" 'w3m-close-window)))

If you use a Dvorak keyboard layout, you can bind . to w3m-previous-buffer and , to w3m-next-buffer instead. Just add the following code to your ~/.emacs:

(eval-after-load 'w3m
  '(progn
     (define-key w3m-mode-map "." 'w3m-previous-buffer)
     (define-key w3m-mode-map "," 'w3m-next-buffer)))

(This is part of the draft for my book on Emacs, to be published by No Starch Press if I’m not too late.)

Emacs and W3M: Toggling between work and the Web

Here’s a handy shortcut that toggles between the W3M web browser and other buffers you’re working on. I use it to quickly switch between code and documentation (or your favorite timewasting site, as it also makes a handy boss key).

Define the function by adding the following code to your ~/.emacs:

(defun wicked/toggle-w3m ()
  "Switch to a w3m buffer or return to the previous buffer."
  (interactive)
  (if (derived-mode-p 'w3m-mode)
      ;; Currently in a w3m buffer
      ;; Bury buffers until you reach a non-w3m one
      (while (derived-mode-p 'w3m-mode)
	(bury-buffer))
    ;; Not in w3m
    ;; Find the first w3m buffer
    (let ((list (buffer-list)))
      (while list
	(if (with-current-buffer (car list)
	      (derived-mode-p 'w3m-mode))
	    (progn
	      (switch-to-buffer (car list))
	      (setq list nil))
	  (setq list (cdr list))))
      (unless (derived-mode-p 'w3m-mode)
	(call-interactively 'w3m)))))

Then bind it to a shortcut key sequence (F7 F7 in this example) by adding the following code to your ~/.emacs:

(global-set-key (kbd " ") 'wicked/toggle-w3m)

You can then use F7 F7 to switch back and forth between your web browser and whatever else you’re working on.

Emacs and w3m: Fake your user agent

In an ideal world, you would never need to make your browser pretend to be a different browser. In reality, a number of websites check for specific browsers such as Mozilla or Internet Explorer, or even specific versions of those browsers. Other websites check for popular search engine crawlers such as the Googlebot in order to display content optimized for that search engine. You may want to change your user agent to work around such limitations, or you might want to change your user agent string just for fun.

The following code allows you to set your user agent (wicked/w3m-set-user-agent), reload the current page using a specified user agent (wicked/w3m-reload-this-page-with-user-agent), and define regular expression matches for URLs to control user agent strings (wicked/w3m-fake-user-agent-sites). To use this, add the following to your ~/.emacs:

 (defvar wicked/w3m-fake-user-agents ;; (1)
   `(("w3m" . ,(concat "Emacs-w3m/" emacs-w3m-version " " w3m-version))
     ("ie6" . "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)")
     ("ff3" . "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1) Gecko/2008070206 Firefox/3.0.1")
     ("ff2" . "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.13) Gecko/20080208 Firefox/2.0.0.13")
     ("ie7" . "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727)")
     ("ie5.5" . "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98)")
     ("iphone" . "Mozilla/5.0 (iPhone; U; CPU iPhone OS 2_0 like Mac OS X; en-us) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile/5A347 Safari/525.20")
     ("safari" . "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_2; en-us) AppleWebKit/525.13 (KHTML, like Gecko) Version/3.1 Safari/525.13")
     ("google" . "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"))
   "*Associative list of user agent names and strings.")

 (defvar wicked/w3m-fake-user-agent-sites ;; (2)
   '(("^https?://www\\.useragentstring\\.com" . "ff2"))
   "*Associative list of regular expressions matching URLs and the agent keyword or value.
 The first matching entry will be used.")

 (defun wicked/w3m-set-user-agent (agent)
   "Set the user agent to AGENT based on `wicked/w3m-fake-user-agents'.
 If AGENT is not defined in `wicked/w3m-fake-user-agents', it is used as the user agent.
 If AGENT is empty, the default w3m user agent will be used."
   (interactive
    (list
     (completing-read "User-agent [w3m]: "
                    (mapcar 'car wicked/w3m-fake-user-agents)
                    nil nil nil nil "w3m"))) ;; (3)
   (if agent
       (progn
        (setq w3m-user-agent
              (or
               (and (string= agent "") (assoc "w3m" wicked/w3m-fake-user-agents)) ;; (4)
               (cdr (assoc agent wicked/w3m-fake-user-agents)) ;; (5)
               agent)) ;; (6)
        (setq w3m-add-user-agent t))
     (setq w3m-add-user-agent nil)))

 (defun wicked/w3m-reload-this-page-with-user-agent (agent)
   "Browse this page using AGENT based on `wicked/w3m-fake-user-agents'.
 If AGENT is not defined in `wicked/w3m-fake-user-agents', it is used as the user agent.
 If AGENT is empty, the default w3m user agent will be used."
   (interactive (list (completing-read "User-agent [w3m]: "
                    (mapcar 'car wicked/w3m-fake-user-agents)
                    nil nil nil nil "w3m")))
   (let ((w3m-user-agent w3m-user-agent)
       (w3m-add-user-agent w3m-add-user-agent))
     (wicked/w3m-set-user-agent agent) ;; (7)
     (w3m-reload-this-page)))

 (defadvice w3m-header-arguments (around wicked activate) ;; (8)
   "Check `wicked/w3m-fake-user-agent-sites' for fake user agent definitions."
   (let ((w3m-user-agent w3m-user-agent)
         (w3m-add-user-agent w3m-add-user-agent)
         (sites wicked/w3m-fake-user-agent-sites))
     (while sites
       (if (string-match (caar sites) (ad-get-arg 1))
         (progn
           (wicked/w3m-set-user-agent (cdar sites))
           (setq sites nil))
       (setq sites (cdr sites))))
     ad-do-it))

wicked/w3m-fake-user-agents sets up a number of common user agents(1) using examples from http://www.useragentstring.com. If you frequently use other user agents, add them to this associative list. wicked/w3m-fake-user-agent-sites sets up some rules for URLs so that you can work around specific websites(2). The first matching rule will be used.

wicked/w3m-set-user-agent can be called from a w3m browser session to set the user agent for all new pages visited. By default, it uses the w3m user agent(3). It will also use the w3m user agent if the agent is blank(4). If the user agent is one of the frequently-used agents defined in wicked/w3m-fake-user-agents, then the corresponding user agent string will be used(5). If not, the string will be used as-is(6). If the agent is nil, the user agent string will be disabled.(7)

You can check a single page using a different user agent by using M-x wicked/w3m-reload-this-page-with-user-agent. It temporarily sets the user agent and then reloads the current page.(7)

The last segment of code modifies the behavior of w3m-header-arguments(8), matching wicked/w3m-fake-user-agents against the URL. This temporarily sets the user agent for matching sites.

Why browse the Web in Emacs?

2014-11-27: Hi, Hacker News! Remember, this post is from 2008 and predates Emacs 24.4. I hear EWW (Emacs Web Wowser?) is pretty cool and have been meaning to try it out. Anyway, on with the show!

“Are you browsing Slashdot in Emacs?”, W- asked me after he glanced at my screen.

With Emacs’ reputation for including everything _and_ the kitchen sink, you probably won’t be surprised to hear that there’s more than one way to surf the Internet using your text editor. With today’s Javascript- and image-heavy websites, it can be hard to believe that anyone would use a text-based browser with limited support for many of the things we take for granted. Still, a Web browser in your text editor can be surprisingly useful. Here are some of the reasons why you might like it:

  • Browsing is faster and less distracting. Forget flashing ads, garish colors, and large images. When you surf the Web in Emacs, you can focus on reading, and you can use all the typical Emacs shortcuts for navigating around. You can view images when you want to. If you need to see something that Emacs doesn’t support, you can easily open the current page in an external Web browser.
  • You can integrate it into your work. With a little bit of Emacs Lisp, you can quickly look up information on the Web based on what you’re currently working on. For example, PHP mode comes with a shortcut that lets you look up the current function’s documentation in the PHP manual. You can look up bug report details, dictionary definitions, and Wikipedia pages with minimal typing, too. If you use Emacspeak, you can set up the web browser to speech-synthesize more than what’s displayed on screen. The more you use Emacs, the more benefits you get from the integration.
  • You can customize everything. You can customize your Emacs experience quickly and easily, and if you spend a lot of time on the Net, you’ll appreciate having your own shortcuts and functions. For example, I’ve completely remapped my keyboard shortcuts to support tabbed browsing on a Dvorak keyboard, and I’ve defined a few functions to make frequently-used commands much easier. You can even use functions to process Web pages and either summarize the information you’re interested in or make pages more navigable. It’s all just Emacs Lisp.
  • You’re safe from browser exploits. No Javascript pop-ups, no image bugs, no browser-based malware that can take over your comuter or steal data. Just content.
  • You need less memory. Why open up a memory-intensive graphical Web-based browser when you’ve got Emacs open anyway?

There’s more than one way to browse the Web in Emacs, of course. Browse-url is a package that makes it easy to open URLs in your preferred browser or browsers. For example, you can use it to browse the Web in Mozilla Firefox, and (of course) you can use it to browse the Web within Emacs itself. For browsing within Emacs, you can use w3m.el, an interface to the external W3M browser, or w3, a Web browser written entirely in Emacs Lisp. Of the two, I prefer w3m.el, which is much faster and more featureful than w3. Both can display graphics, tables, and frames, and w3 supports stylesheets.

More about Emacs and browsing the Web soon! Planned projects for this chapter of Wicked Cool Emacs:

*** Project XXX: Browse the Web
*** Project XXX: Open the current webpage in an external browser
*** Project XXX: Different browsers for different pages
*** Project XXX: Toggle between Web and work
*** Project XXX: Quick search
*** Project XXX: Customize your keymap
*** Project XXX: Download files
*** Project XXX: Add access keys
*** Project XXX: Use social bookmarking
*** Project XXX: Typeahead
*** Project XXX: Preview HTML
*** Project XXX: Read Web pages as news
2014-11-27: You can find more comments on Hacker News.