On this page:

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.

Why browse the Web in Emacs?

“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 qucikly 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

Emacs and PHP: On-the-fly syntax checking with Flymake

The dreaded white screen of nothingness usually means that I’ve misplaced a quotation mark or brace somewhere in my PHP code. On-the-fly syntax checking in Eclipse helped me find those errors quickly because I could scan the right scrollbar for areas marked with red. I knew that shifting to Emacs wouldn’t automatically cure me of the propensity to mismatch my parentheses. If I could get on-the-fly syntax checking working in Emacs, I’d save myself a lot of time.

It took me a while to sort out various configuration problems. Most were due to the fact that PHP didn’t report parse errors with my original configuration, even though I had uncommented the line after “Show only errors”. As it turned out, the error_reporting option in php.ini needs to include E_PARSE in order for php to report parsing error details. Here’s the value I’m currently using in /etc/php.ini:

error_reporting = E_ERROR|E_COMPILE_ERROR|E_CORE_ERROR|E_PARSE

Flymake is the package responsible for on-the-fly syntax checking in Emacs. Out of the box, it supports C, C++, XML, XHTML, Perl, Java, TeX, and IDL. To load Flymake and add support for PHP, add the following to your ~/.emacs:

(require 'flymake)

(defun flymake-php-init ()
  "Use php to check the syntax of the current file."
  (let* ((temp (flymake-init-create-temp-buffer-copy 'flymake-create-temp-inplace))
	 (local (file-relative-name temp (file-name-directory buffer-file-name))))
    (list "php" (list "-f" local "-l"))))

(add-to-list 'flymake-err-line-patterns 
  '("\\(Parse\\|Fatal\\) error: +\\(.*?\\) in \\(.*?\\) on line \\([0-9]+\\)$" 3 4 nil 2))

(add-to-list 'flymake-allowed-file-name-masks '("\\.php$" flymake-php-init))

;; Drupal-type extensions
(add-to-list 'flymake-allowed-file-name-masks '("\\.module$" flymake-php-init))
(add-to-list 'flymake-allowed-file-name-masks '("\\.install$" flymake-php-init))
(add-to-list 'flymake-allowed-file-name-masks '("\\.inc$" flymake-php-init))
(add-to-list 'flymake-allowed-file-name-masks '("\\.engine$" flymake-php-init))

(add-hook 'php-mode-hook (lambda () (flymake-mode 1)))
(define-key php-mode-map '[M-S-up] 'flymake-goto-prev-error)
(define-key php-mode-map '[M-S-down] 'flymake-goto-next-error)

Evaluate that code, open one of your PHP files, and intentionally break it. The syntax error should be highlighted. To change the highlighting, move your point to the error and type M-x customize-face. Accept the default (flymake-errline), then customize it as desired. Don’t forget to save your customizations for future sessions.

If your syntax errors are not highlighted and you get a message like this:

Configuration error occured while running (php -f test_flymake.php -l). flymake will be switched OFF

double-check your /etc/php.ini to make sure that E_PARSE is included as one of the options for error_reporting. You can check the output by running php -f yourfile.php -l. You should see the line number of the parse error. Make sure that this matches the regular expression added to flymake-err-line-patterns in your ~/.emacs. If your PHP returns a slightly different message, modify your flymake-err-line-patterns accordingly.

Flymake can save you a lot of programmer frustration for the cost of a little CPU time. Use it to check for errors before you save files or commit them to your source code control repository, and you and other developers will be much happier.

(UPDATE: Fixed typo in flymake-php-init)

Emacs Gnus: Filter Spam

(draft for an upcoming book called Wicked Cool Emacs)

Ah, spam, the bane of our Internet lives. There is no completely
reliable way to automatically filter spam. Spam messages that slip
through the filters and perfectly legitimate messages that get
labelled spam are all part of the occupational hazards of using the
Internet.

The fastest way to filter spam is to use an external spam-filtering
program such as Spamassassin or Bogofilter, so your spam can be
filtered in the background and you don’t have to spend time in Emacs
filtering it yourself. In an ideal world, this would be done on the
mail server so that you don’t even need to download unwanted
messages. If your inbox isn’t full of ads for medicine or stocks, your
mail server is probably doing a decent job of filtering the mail for
you.

Server-based mail filtering

As spam filtering isn’t an exact science, you’ll want to find out how
you can check your spam folder for misclassified mail. If you download
your mail through POP, find out if there’s a webmail interface that
will allow you to check if any real mail has slipped into the junk
mail pile. If you’re on IMAP, your mail server might automatically
file spam messages in a different group. Here’s how to add the spam
group to your list of groups:

  1. Type M-x gnus to bring up the group buffer.
  2. Type ^ (gnus-group-enter-server-mode).
  3. Choose the nnimap: entry for your mail server and press RET (gnus-server-read-server).
  4. Find the spam or junk mail group if it exists.
  5. Type u (gnus-browse-unsubscribe-current-group) to toggle the subscription. Subscribed groups will appear in your M-x gnus screen if they contain at least one unread message.

Another alternative is to have all the mail (spam and non-spam)
delivered to your inbox, and then let Gnus be in charge of filing it
into your spam and non-spam groups. If other people manage your mail
server, ask them if you can have your mail processed by the spam
filter but still delivered to your inbox. If you’re administering your
own mail server, set up a spam filtering system such as SpamAssassin
or BogoFilter, then read the documentation of your spam filtering
system to find out how to process the mail.

Spam filtering systems typically add a header such as “X-Spam-Status”
or “X-Bogosity” to messages in order to indicate which messages are
spam or even how spammy they are. To check if your mail server tags
your messages as spam, open one of your messages in Gnus and type C-u
g (gnus-summary-show-article) to view the complete headers and
message. If you find a spam-related header such as X-Spam-Status, you
can use it to split your mail. Add the following to your ~/.gnus:

 (setq spam-use-regex-headers t) ;; (1)
 (setq spam-regex-headers-spam "^X-Spam-Status: Yes")   ;; (2)
 (require 'spam) ;; (3)
 (spam-initialize) ;; (4)

This configures spam.el to detect spam based on message
headers(1). Set spam-regex-headers-spam to a regular expression
matching the header your mail server uses to indicate spam.(2) This
configuration should be done before the spam.el library is loaded(3)
and initialized(4), because spam.el uses the spam-use-* variables to
determine which parts of the spam library to load.

In order to take advantage of this, you’ll also need to add a rule
that splits spam messages into a different group. If you haven’t set
up mail splitting yet, read qthe instructions on setting up fancy mail
splitting in “Project XXX: Organize mail into groups”. Add (:
spam-split) to either nnmail-split-fancy or nnimap-split-fancy,
depending on your configuration. For example, your ~/.gnus may look
like this:

(setq nnmail-split-fancy
'(
;; ... other split rules go here ...
(: spam-split)
;; ... other split rules go here ...
"mail.misc")) ; default mailbox

(draft for an upcoming book called Wicked Cool Emacs, more to come!)

Emacs Gnus: Organize Your Mail

People handle large volumes of mail in different ways. Keeping
everything in one mailbox can quickly become unmanageable because
messages you need to read get lost among messages you don’t need to
read.

You can move mail manually by selecting them in the summary buffer and
typing B m (gnus-summary-move-article). Then type the name of the
group to which you would like to move the message. The group will be
created if it doesn’t exist.

To move multiple messages, mark them with #
(gnus-summary-mark-as-processable) and then type B m
(gnus-summary-move-article). To unmark a message, type M-#
(gnus-summary-unmark-as-processable). To unmark all messages, type M P
U (gnus-summary-unmark-all-processable).

Automatically filing mail

Moving messages by hand is tedious and time-consuming. One way to deal
with this is to set up rules that automatically file mail into
different groups (or folders, as they’re called in other mail
clients). Gnus calls this “splitting” mail, and you can split mail on
IMAP servers as well as mail downloaded from POP3 servers to your
computer.

For example, if you’re using Gnus to read mail from an IMAP server,
you can split your messages by adding this to your ~/.gnus:

 (setq nnimap-split-inbox "INBOX") ;; (1)
 (setq nnimap-split-predicate "UNDELETED") ;; (2)
 (setq nnimap-split-rule
       '(
         ("INBOX.emacs" "^Subject:.*emacs")
         ("INBOX.work" "^To:.*[email protected]")    
         ("INBOX.personal" "^To:.*[email protected]")    
         ("INBOX.errors" "^From:.*\\(mailer.daemon\\|postmaster\\)")   
        )) 

If you use a different inbox, change the value of
nnimap-split-inbox(1). Any messages in the inbox will be split
according to nnimap-split-rule(2), which is a list where each element
is a list containing the group’s name and a regular expression
matching the header of messages that should be filed in the group. In
this example, Gnus will move mail with subjects containing the word
“emacs” to INBOX.emacs, mail directed to [email protected] to the
INBOX.work group, mail directed to [email protected] to the
INBOX.personal group, and mail error messages to INBOX.errors. All
other messages will be stored in INBOX.

If you’re downloading your mail from a POP3 server and storing it in
nnml, add this to your ~/.gnus instead:

 (setq nnmail-split-methods
      '(
        ("mail.emacs" "^Subject:.*emacs")
        ("mail.work" "^To:.*[email protected]")    
        ("mail.personal" "^To:.*[email protected]")    
        ("mail.errors" "^From:.*\\(mailer.daemon\\|postmaster\\)")   
       )) 

All other messages will be stored in mail.misc.

Start M-x gnus again, and your mail will be split into the different
groups.

Where are my groups?

If you don’t see your new groups in the group buffer displayed by M-x
gnus, type A A (gnus-group-list-active) to see all the groups. Go to
the group that you would like to add to the group buffer, then type u
(gnus-group-unsubscribe-current-group) to toggle its subscription. In
this example, INBOX.automated is not subscribed to, but INBOX is.

 U    13: INBOX.automated 
      76: INBOX 

When you type M-x gnus again, you’ll see your subscribed groups if
they have unread messages.

nnimap-split-rule and nnmail-split-methods allow you to filter
interesting or uninteresting mail into different groups based on their
headers. Gnus comes with an even more powerful mail splitting engine.
In fact, Gnus comes with “fancy mail splitting.”

Fancy mail splitting

With fancy mail splitting and some configuration, you can split mail
based on a combination of criteria. You can even manually file a
message and have Gnus automatically file incoming replies in the same
group.

To configure an IMAP connection to use fancy mail splitting, add the
following to your ~/.gnus:

 (setq nnimap-split-inbox "INBOX")
 (setq nnimap-split-predicate "UNDELETED")
 (setq nnmail-split-fancy ;; (1)
       '(|                                ;; (2)
         (: gnus-registry-split-fancy-with-parent) ;; (3)
         ;; splitting rules go here       ;; (4)
         "INBOX"                          ;; (5)
        ))
 (setq nnimap-split-rule 'nnmail-split-fancy)
 (setq nnmail-split-methods 'nnimap-split-fancy) ;; (6)
 (gnus-registry-initialize) ;; (7)

This configures IMAP to use the nnmail-split-fancy function to
determine the group for messages. Note that we’re setting the
nnmail-split-fancy variable here. If you want to process your IMAP
mail separately from your other mail, you can set the
nnimap-split-fancy variable instead. If so, also set nnimap-split-rule
to ‘nnimap-split-fancy. Using nnmail-split-fancy here makes the other
examples easier to understand, though.

The nnmail-split-fancy variable controls the splitting behavior(1). The
“|” symbol means that that the first matching rule is used(2). For
example, if the message being processed is a reply to a message that
Gnus knows about, then the gnus-registry-split-fancy-with-parent
function will return the name of the group, and nnmail-split-fancy
will file the message there(3). You can add other splitting rules as
well(4). If messages don’t match any of these rules, the last rule
specifies that the messages will be filed in INBOX(5). Set
nnmail-split-methods to nnimap-split-fancy as well in order to work
around some assumptions in other parts of the code(6). After that,
initialize the Gnus registry(7), which is responsible for tracking
moved and deleted messages. This allows you to automatically split
replies into the same folders as the original messages.

To configure fancy mail splitting with an nnml backend (suggested
configuration for POP3), add the following to your ~/.gnus instead:

 (gnus-registry-initialize)
 (setq nnmail-split-fancy                 
       '(|                                
         (: gnus-registry-split-fancy-with-parent)
         ;; splitting rules go here       
         "mail.misc"                          ;; (1)
        ))
 (setq nnmail-split-methods 'nnmail-split-fancy)    

This code is similar to the IMAP example, except that the default
mailbox name for nnml is mail.misc(1).

Here’s how the previous rules in nnmail-split-methods would be
translated to nnmail-split-fancy rules for an IMAP configuration:

 (setq nnmail-split-fancy
      '(|
        (: gnus-registry-split-fancy-with-parent)
         ;; splitting rules go here       
        (from mail "INBOX.errors")   ;; (1)
        (any "[email protected]" "INBOX.work")   ;; (2)
        (any "[email protected]" "INBOX.personal") ;; 
        ("subject" "emacs" "INBOX.emacs") ;; (3)
        "INBOX"    ;; or "mail.misc" for nnml/POP3
       )) 

The from keyword matches against the “From”, “Sender”, and
“Resent-From” fields, while the mail keyword matches common mail
system addresses(1). The corresponding to keyword matches against
the “To”, “Cc”, “Apparently-To”, “Resent-To” and “Resent-Cc” headers,
while any matches the fields checked by the from and to
keywords(2). You can also compare against the subject
and other headers(3).

You can use logic in splitting rules, too. For example, if you like
reading the jokes on [email protected], but you don’t like
the ones sent by [email protected] (he not only has a bad sense of
humor, but also likes picking on Emacs!), you can use a rule like
this in your nnmail-split-fancy:

         ;; ... other splitting rules go here...
         (any "joke-mailing-list@exam[email protected]"   ;; (1)
              (| (from "[email protected]" "INBOX.junk") ;; (2)
                 "INBOX.jokes")) ;; (3)
         ;; ... other splitting rules go here

The first rule matches all messages with
[email protected]” in from- or to-related headers.
Matching messages are processed with another split rule, which moves
messages from [email protected] to a separate group(2) and files the
other messages in INBOX.jokes(3). To learn more about creating complex
rules, read the Gnus Info manual for “Fancy Mail Splitting”.

Emacs Gnus: Searching Mail

There are several ways to find messages in Emacs. From the summary
buffer, you can use / o (gnus-summary-insert-old-articles) to display
all or some old messages. You can then scan through the headers in the
summary buffer by using C-s (isearch-forward), or you can limit the
displayed messages with these commands:

Messages from a given author / a gnus-summary-limit-to-author
Messages whose subjects matching a given regular expression / / gnus-summary-limit-to-subject
Messages that match a given extra header / x gnus-summary-limit-to-extra-headers
Messages at least N days old / t gnus-summary-limit-to-age

Limits work on the messages that are currently displayed, so you can
apply multiple limits. If you make a mistake, use / w
(gnus-summary-pop-limit) to remove the previous limit. You can repeat
/ w (gnus-summary-pop-limit) until satisfied. To remove all the
limits, type C-u / w (gnus-summary-popl-limit).

If you specify a prefix, the limit’s meaning is reversed. For
example, C-u / a (gnus-summary-limit-to-author) will remove the
messages from the matching author or authors.

You can use Gnus to search the currently-displayed messages by using
M-s (gnus-summary-search-article-forward) and M-r
(gnus-summary-search-article-backward).

If you want to search a lot of mail, you’ll find NNIR handy. NNIR is a
front-end to mail search engines which can index your mail and return
search results quickly. If you want to use NNIR with a local or remote
IMAP server, you will need to use nnir.el and imap.el. If you download
your mail using fetchmail or connect to a POP3 server and use an nnml
backend, you can use NNIR with a search engine such as swish-e to
search your ~/Mail directory efficiently.

1.6.7.1 Setting up IMAP and NNIR

If you use IMAP, then your mail is stored on the mail server and
you’ll need to use the IMAP search interface to search through
it. Download nnir.el from
http://www.emacswiki.org/cgi-bin/wiki/download/nnir.el and save it to
your ~/elisp directory. You will also need an imap.el that is newer
than the one that comes with Emacs 22. Download imap.el from
http://www.emacswiki.org/cgi-bin/wiki/download/imap.el and save it to
your ~/elisp directory as well. Because Gnus comes with an older
version of imap.el, you will need to make sure that the new version of
imap.el is loaded. Add the following to your ~/.gnus:

(add-to-list 'load-path "~/elisp")
(load-file "~/elisp/imap.el")
(require 'nnir)

Restart your Emacs. You can check if the correct version of imap.el
has been loaded by typing M-x locate-library and specifying
imap.el. If Emacs reports “~/elisp/imap.el”, then Gnus is configured
to use the updated imap.el.

1.6.7.2 Setting up POP3 and NNIR

If you use the configuration for POP3 that is suggested in this
chapter, then your mail is stored in the nnml backend, which uses one
file per message. To search this using NNIR, to install nnir.el and an
external search mail engine. The Namazu search engine runs on Linux,
UNIX, and Microsoft Windows, so that’s what we’ll talk about here. To
find and configure other mail search engines supported by NNIR, check
out the comments in nnir.el.

First, you’ll need to download and install Namazu. If Namazu is
available as a package for your distribution, install it that way, as
it depends on a number of other programs. An installer for Microsoft
Windows can be found at http://www.namazu.org/windows/ . If you need
to build Namazu from source, you can get the source code and instructions
from http://www.namazu.org .

After you’ve installed Namazu, create a directory for Namazu’s index
files, such as ~/.namazu-mail. Then index your mail by typing this at
the command-line:

mknmz --mailnews -O ~/.namazu-mail ~/Mail

and add the following to your ~/.gnus:

(add-to-list 'load-path "~/elisp")
(require 'nnir)
(setq nnir-search-engine 'namazu)
(setq nnir-namazu-index-directory (expand-file-name "~/.namazu-mail"))
(setq nnir-namazu-remove-prefix (expand-file-name "~/Mail"))
(setq nnir-mail-backend gnus-select-method)
1.6.7.3 Searching your mail with NNIR

From the group buffer displayed by M-x gnus, you can type G G
(gnus-group-make-nnir-group) to search your mail for a keyword.

If you’re using the Namazu search engine, then you can use more
sophisticated search queries such as:

Linux Emacs messages that contain both “Linux” and “Emacs”
Linux or Emacs messages that contain either “Linux” or “Emacs”
Emacs not Linux messages that contain “Emacs” but not “Linux”
Emacs and (Linux or Windows) messages that contain “Emacs” and either “Linux” or “Windows”
“apple pie” messages that contain the phrase “apple pie”
{apple pie} messages that contain the phrase “apple pie”
+from:[email protected] messages with [email protected] in the From: header
+subject:”apple pie” messages with the phrase “apple pie” in the Subject: header
+subject:apple +subject:pie messages whose Subject: headers contain both “apple” and “pie”

If
matching messages are found, then you will see a temporary group with
the results. Although you can’t delete messages from this view,
reading and replying to these messages is the same as reading and
replying to regular messages.

To see a message in its original context, type G T
(gnus-summary-nnir-goto-thread) from the summary buffer. This opens
the message’s original group. If Gnus asks you how many articles to
load, press RET to accept the default of all the articles.


This is a draft for the Wicked Cool Emacs book I’m working on. =) Hope it helps!