Emacs function to add new path elements to the $PATH environment variable

A very simple eLisp function to add new path elements to the PATH environment variable. Very useful for adding new comint executables from within .emacs/init.el files.

(defun my-add-path (path-element)
 "Add the specified path element to the Emacs PATH"
  (interactive "DEnter directory to be added to path: ")
  (if (file-directory-p path-element)
    (setenv "PATH"
       (concat (expand-file-name path-element)
               path-separator (getenv "PATH")))))

Quickly diff the changes made in the current buffer with its file

Update (23rd Jan 2010): Separated the key-assignment and  function definition.

A simple function to quickly do a diff of the current buffer contents with its underlying file. Very useful if the file has been changed outside (e.g., a log file).

;; Diff the current buffer with the file contents
(defun my-diff-current-buffer-with-disk ()
 "Compare the current buffer with it's disk file."
 (interactive)
 (diff-buffer-with-file (current-buffer)))
(global-set-key (kbd "C-c w") 'my-diff-current-buffer-with-disk)

Google Search from within Emacs

A quick and dirty eLisp function for searching on the internet from within Emacs. The default is to search using Google, but you can add to the *internet-search-urls* variable to setup additional search URLs.

By default, the search term is appended at end of the URL – however, you can also encode the specific search term insertion point in the URL by marking the position using the “%s” marker.

;;; The custom search URLs
(defvar *internet-search-urls*
 (quote ("http://www.google.com/search?ie=utf-8&oe=utf-8&q=%s"
         "http://en.wikipedia.org/wiki/Special:Search?search=")))

;;; Search a query on the Internet using the selected URL.
(defun search-in-internet (arg)
 "Searches the internet using the ARGth custom URL for the marked text.

If a region is not selected, prompts for the string to search on.

The prefix number ARG indicates the Search URL to use. By default the search URL at position 1 will be used."
 (interactive "p")

 ;; Some sanity check.
 (if (> arg (length *internet-search-urls*))
      (error "There is no search URL defined at position %s" arg))

  (let ((query                          ; Set the search query first.
    (if (region-active-p)
      (buffer-substring (region-beginning) (region-end))
    (read-from-minibuffer "Search for: ")))

  ;; Now get the Base URL to use for the search
  (baseurl (nth (1- arg) *internet-search-urls*)))

  ;; Add the query parameter
  (let ((url
    (if (string-match "%s" baseurl)
      ;; If the base URL has a %s embedded, then replace it
         (replace-match query t t baseurl)
    ;; Else just append the query string at end of the URL
      (concat baseurl query))))
 
   (message "Searching for %s at %s" query url)
   ;; Now browse the URL
   (browse-url url))))

Importing contacts from OSX Addressbook to Emacs BBDB

A major aspect of using Emacs is that it is more than a text editor – it is more of an application platform – some would call it an Operating System – that allows a host of applications to run within the same context and session – and vastly enrich the user experience. This is in fact a primary reason why many Emacs users spend their entire computer interaction via Emacs.

This unique aspect of Emacs is made possible by the availability of Emacs Lisp as a first class scripting/programming interface for the editor – and has made possible application packages such as W3 (a web browser), Gnus (the NNTP and mail reader), Eshell (a lisp based shell), Wanderlust (a very capable email client), and the Insidious Big Brother Database – aka BBDB – which is a contact manager and the subject of this post.

(BTW, the list of application is only a very small fraction of what is actually available on Emacs – see www.emacswiki.org for a ton of other packages).

As EmacsWiki points out, BBDB is:

“A complete address book for nearly every email and news client written for Emacs, and its functionality supports (by default) making entries in the address book automatically when reading email or posts by people, and easy lookup of addresses while composing messages.”

In essence, it is an always available address book that works with other packages such as mail, Gnus and org-mode to provide a easy to access repository of contact information. The repository itself is a plain text lisp file which by default is stored as ~/.bbdb.

However, as with any contact manager, the problems are usually with:

  1. Initial data import, and
  2. Synchronization with other repositories and devices

For my platform (Apple OSX), the first problem above translates to data import from my primary OS level address book – the AddressBook.app. The second problem is not much of an issue for me since I use AddressBook.app as the primary contact list elsewhere and sync my devices to that. For keeping BBDB in sync, I have a cron job to automate the scripts below.

The contacts import to BBDB requires a data conversion of the address from custom format in which AddressBook.app stores the contacts to the BBDB lisp format. The steps required are as follows:

  1. Extract the records from AddressBook.app
  2. Parse and reformat the relevant fields that BBDB requires, and
  3. Output the reformatted records in the BBDB lisp format

Luckily, for step # 1, an open source command line utility already exists – appropriately called contacts. It is available from http://gnufoo.org/contacts/ and is a svelte 194KB download. This utility allows querying of the OSX Address book and extraction of specific fields and records. The output is a simple CSV text file.

For step # 2 and #3, additional scripting is required. I have written a simple Ruby script called contacts2bbdb.rb to run the contacts utility and output the BBDB repository file:

#!/usr/bin/env ruby -w
#
# Filename: contacts2bbdb.rb
# Description: Converts addresses from OSX Addressbook.app to BBDB format
# Author: Anupam Sengupta (anupamsg ... A-T ... G - M - A - I - L )
# Maintainer: Anupam Sengupta
#
# (c) 2007-2016 Anupam Sengupta.
#
# Created: Fri May 25 15:53:22 2007
# Version: 1.0
# Last-Updated:
#           By: Anupam Sengupta
#     Update #: 733
# URL: https://slashusr.wordpress.com
# Keywords: `BBDB’, ‘OSX’, ‘contacts’, ‘convert’
# Compatibility: GNU Emacs 21 and above
#
#--------------------------------------------------------------------
#
# Commentary:
#
#  Converts the addresses and contacts from Apple OSX’s system addressbook
#  format (Addressbook.app) to Emacs’ BBDB format.
#
#  Requires the following additional software:
#
#  1. Ruby V1.8 and above (http://www.ruby-lang.org/)
#  2. Big Brother Database (BBDB) package for Emacs (http://bbdb.sourceforge.net/)
#  3. The ‘contacts’ program to read Addressbook’s contacts
#     (http://gnufoo.org/contacts/)
#
# Usage:
#
#  1. Install Ruby, BBDB and contacts, if not already present
#  2. Backup the OSX Address book (export the addresses as addressbook archive)
#  3. Run this Ruby script to generate the converted records in BBDB format in the STDOUT
#  4. Save the STDOUT output of this script to bbdb.new
#
#     $ ruby contacts2bbdb.rb > bbdb.new
#
#  5. Replace your .bbdb file with bbdb.new
#
#--------------------------------------------------------------------
#
# Change log:
#
#
#--------------------------------------------------------------------
#
# License: GNU GPL V2.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING.  If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street, Fifth
# Floor, Boston, MA 02110-1301, USA.
#--------------------------------------------------------------------
#
Delim = “\t”                    # Default delimiter
ContactsProg = ‘/usr/bin/env contacts’ # The contacts program
#
ContactsProgParams = ‘-H -l’
#
# A map between the LDIF field names and the actual field name
ContactFields = {
:fn => ‘firstName’,
:ln => ‘lastName’,
:c  => ‘company’,
:nn => ‘nickName’,
:he => ‘homeEmail’,
:we => ‘workEmail’,
: oe => ‘otherEmail’,
:hp => ‘Home’,
:mp => ‘Mobile’,
:Mp => ‘Main’,
:wp => ‘Work’,
}
#
ContactFormatOpts = ContactFields.keys #  Options to pass to the contacts program
ContactsProgFormat =  “‘%” + ContactFormatOpts.inject { |s, f| s.to_s + “#{Delim}%#{f.to_s}” } + “‘“
ContactsFullExec = “#{ContactsProg} #{ContactsProgParams} -f #{ContactsProgFormat}”
#
output = `#{ContactsFullExec}`.split(/\n/) # Read the output of contacts program
#
# Start parsing the contacts output
records = output.map do |line|
record = Hash.new(nil)
line.chomp.split(Delim).each_with_index { |f, i| record[ContactFields[ContactFormatOpts[i]]] = f.strip unless f =~ /^\s*$/ }
record
end
#
# Start outputing the details to STDOUT
puts <<END
;; -*-coding: utf-8-emacs;-*-
;;; file-version: 6
END
#
for r in records do
r[‘nickName’] = nil           # No need for the nick names.
outs = %w{ firstName lastName nickName company }.inject(“[“) { |s, f| s + (r[f] ? “\”#{r[f]}\” “ : “nil “) }
outs = %w{ Home Main Mobile Work}.inject(outs + “(“) { |s, f| r[f] ? s + “[\”#{f}\” \”#{r[f].strip}\”] “ : s } + “) “
outs = %w{ homeEmail workEmail otherEmail }.inject(outs + “ nil (“) { |s, f| r[f] ? s + “\”#{r[f]}\” “ : s } + “) “
outs += “((creation-date . \”2009-02-08\”) (timestamp . \”2009-02-08\”)) nil]”
puts outs
end
# End of contacts2bbdb.rb script

A companion shell script to automate the execution of the Ruby program and also backup the previous BBDB file is also provided. Before usage, please edit the BBDB folder and file names:

#!/bin/sh
#
# Filename: contacts2bbdb.sh
# Description: Converts addresses from OSX Addressbook.app to BBDB format
# Author: Anupam Sengupta (anupamsg@gmail.com)
# Maintainer: Anupam Sengupta
#
# (c) 2007-2016 Anupam Sengupta.
#
# Created: Fri May 25 15:53:22 2007
# Version: 1.0
# Last-Updated:
#           By: Anupam Sengupta
#     Update #: 740
# URL: https://slashusr.wordpress.com
# Keywords: `BBDB’, ‘OSX’, ‘contacts’, ‘convert’
# Compatibility: GNU Emacs 21 and above
#
#--------------------------------------------------------------------
#
# Commentary:
#
# Runs the export of OS X Address Book contacts to the Emacs BBDB file.
#
# Requires:
#   1. The contacts2bbdb.rb Ruby script
#      (https://slashusr.wordpress.com/)
#   2. The Ruby interpreter (Version 1.8 and above)
#      (http://www.ruby-lang.org/)
#   3. The Big Brother Database (BBDB) Emacs Package
#      (http://bbdb.sourceforge.net/)
#   4. The contacts command line program to extract the records
#      (http://gnufoo.org/contacts/)
#
# Usage:
#   1. Backup the Addressbook.app’s addresses
#   2. Install BBDB and ‘contacts’, if not already present
#   3. Edit the BBDBDIR and RUBYPROG variables below
#   4. Open Terminal.app and run this script
#   5. The script will also create a backup of the previous bbdb file
#
#
#
# TODO: Edit these variables to match the file locations
BBDBDIR=$HOME/.emacs.d/data     # Edit this to match location of the bbdb file
BBDBFILE=bbdb                   # Edit this to match your bbdb file name
RUBYPROG=$HOME/bin/contacts2bbdb.rb # Name and loction of the Ruby Script
#
#######################################  Do not edit beyond this point !
#
RUBYEXEC=`which ruby`
#
if [ -x ${RUBYEXEC} ]; then
cp ${BBDBDIR}/$BBDBFILE ${BBDBDIR}/bbdb.bak
${RUBYEXEC} ${RUBYPROG} > $BBDBDIR/$BBDBFILE
fi
echo “BBDB Export and conversion completed.”
#
# End of contacts2bbdb.sh

Do remember to take a backup of your existing BBDB file as well as a backup of the OSX address-book before running the scripts!

Enjoy!

Update [17th Aug 2009]: Emacs-fu has a nice bbdb tutorial at emacs-fu: managing e-mail addresses with bbdb

Tips for using emacsclient using Emacs 23.1 daemon mode

In an earlier post I had listed the server-mode mechanism to allow client/server editing using Emacs. However, this require some setup and also an active Emacs session.

With the latest version of Emacs (23.1), a new mechanism to invoke Emacs in a server mode has been introduced. Basically, emacs can be invoked with the –daemon option from the shell command line:

$ emacs --daemon

This will run emacs in the background as a daemon which will be listening in to emacsclient connections. To actually start a edit session, use emacsclient from the command line as before with the file name as a parameter.

A couple of new options have been added to the 23.1 emacsclient which allow the client to either

  1. Invoke a terminal editing session (via the -t option to emacsclient), or
  2. Create or reuse a GUI frame for the editing session (default behavior)

The advantage here is that Emacs can now truly act as a server (without any visible window or terminal session) and can be added to the logon/start up scripts.

Tips for using emacsclient and server-mode on OSX

Emacs is a great editor, but has one setback – it is slow to startup if you have loads of packages to load. On my G4 iBook, it takes around 45 seconds before Emacs becomes usable (OK – I use lots of packages).

However, Emacs is not meant to be restarted every so often. The canonical usage is to start Emacs once, invoke the server mode (see EmacsClient) and then use the emacsclient from the command line to invoke the editor instance when needed. I.e., the classic client/server model for editing!

Note that by default, this uses local sockets and hence the clients can connect only to the local machine’s server. However, there is an alternate mechanism to use standard TCP/IP sockets, which allows connections to remote Emacs servers. See the emacsclient info page  for details.

(Note: With the latest 23.1 version of Emacs, there is an alternate mechanism to start Emacs in a server mode – will post this in a future article).

In order to enable this feature, server-mode needs to be run within an active Emacs session (V22 and above). This can be achieved by:

M-x server-start

Alternatively, you can add the following line at end of your .emacs file:

(server-start)

Note that a running Emacs session needs to be present before the clients can connect.

The next step is to invoke emacsclient from the command line (or from a script) with the file name to edit.

$ emacsclient <file to edit>

This will cause a new file buffer with the requested file to be opened in the running Emacs session. The emacsclient that invoked the edit will block till the running Emacs returns control via ‘C-x #’ (server-edit)

You can use the -n option to the emacsclient invocation to prevent the blocking.

On my system, I have aliased the ‘emacsclient’ binary to be ‘ec’, which is much simpler to type.

I.e., in my `.bashrc’, I have

alias ec emacsclient

I have also defined $EDITOR to use ‘emacsclient’ when possible, and ‘vi’ otherwise. However, instead of directly assigning to the $EDITOR environment variable, I have a small shell-script to define the default editor I want to use. This script is then assigned to the $EDITOR variable.

The code for the default-editor shell-script (named ‘default-editor’) is:

#!/bin/bash
# Set up a default editor for the shell
# Use Emacs if already open, and vi in other cases (including fallback)

# Note that this will set the default emacsclient, which may not be what you want
# if multiple versions of emacs are available. In that case, you can put the absolute path
# of the emacsclient that needs to be used.
# E.g., the Cocoa 23.1 emacsclient on OSX is actually located at:
# /Applications/Emacs.app/Contents/MacOS/bin/emacsclient
EMACS_EDITOR=`which emacsclient`

if [ -x "$EMACS_EDITOR" ]; then
   $EMACS_EDITOR -a vi "$@"
else
   vi "$@"                     # Never fails!
fi

And then, in the .bashrc file, I have:

if [ -x $HOME/bin/default_editor ]; then
   export EDITOR=$HOME/bin/default_editor
else
   export EDITOR=`which vi`
fi

BTW, the code above assumes that you use bash as the primary shell in your terminal. You can however trivially modify the scripts above for your specific shell.

Setting the PATH variable from within Emacs

A Small function to set the PATH variable from within Emacs. You can define the function and the path definitions in your .emacs file:

Very useful for OS X, where the default path is set by plists.

;; Define a function to setup additional path
 (defun my-add-path (path-element)
    "Add the specified path element to the Emacs PATH"
    (interactive "DEnter directory to be added to path: ")
    (if (file-directory-p path-element)
        (setenv "PATH"
                (concat (expand-file-name path-element)
                         path-separator 
                         (getenv "PATH")))))

and use it as:

;;; Set localized PATH for OS X
 (if (fboundp 'my-add-path)
     (let ((my-paths (list
                    "/opt/local/bin"
                    "/usr/local/bin"
                    "/usr/local/sbin"
                    "/usr/local/mysql/bin"
          "~/bin")))
         (dolist (path-to-add my-paths (getenv "PATH"))
         (my-add-path path-to-add))))