basic emacs lisp idioms
  Home FAQ Contact Sign in
comp.emacs only
 
Advanced search
POPULAR GROUPS

more...

 Up
basic emacs lisp idioms         

Group: comp.emacs · Group Profile
Author: xahlee
Date: Jun 14, 2008 06:35

Here's a short tutorial i wrote up today that is a basic collection of
Emacs Lisp Idioms.

The HTML version with links, syntax coloring, is at:
http://xahlee.org/emacs/elisp_idioms.html

The text version follows. Comments, corrections, suggestions welcome.

-----------------------------
This page collects some basic emacs lisp programing patterns related
to text processing.

This page is grouped into 2 sections: Interactive and Batch. The
Interactive section focuses on idioms of writing the type of commands
you call when actively editing. For example, looking up the word under
cursor in google search, replace certain words in current region,
insert XML template, rename a given function in the current programing
project, etc. The Batch section focuses on batch style text
processing, typically the type of tasks one would do in unix shell
tools or Perl. For example, find and replace on a list of given files
or dir, run XML validation on a bunch of files.

The idioms on this page contains only very basic ones, suitable for
beginning elisp programer.

You should first be familiar with basic emacs functions that get
cursor position, move cursor, search text, inserting and deleting
text. See Elisp Common Functions Reference.

------------------------------
Interactive Command Idioms

Grabbing Text

Grab the text of given beginning position and ending position.

; get the string from buffer
(setq myStr (buffer-substring myStartPos myEndPos))
(setq myStr (buffer-substring-no-properties myStartPos myEndPos))

Emacs's string can have properties for the purposes of syntax
coloring, active button, hypertext, etc. The “buffer-substring-no-
properties” function just return a plain string without these
properties. However, most functions that takes string as argument can
also accept strings that has properties.

Reference: Elisp Manual: Buffer-Contents.

------------------------------

Grabbing the current word, line, sentence, url, file name etc.

; grab a thing at point. The “thing” is a semantic unit. It can be a
; word, symbol, line, sentence, filename, url and others.
(setq myStr (thing-at-point 'word)) ; grab the current word
(setq myStr (thing-at-point 'symbol)) ; grab the current word with
hyphens or underscore
(setq line (thing-at-point 'line)) ; grab the current line

; grab the start and end positions of a line (or any other thing)
(setq myBoundaries (bounds-of-thing-at-point 'line))
Note that, when the thing is a “symbol”, it usually means any
alphanumeric sequence with dash “-” or underscore “_” characters. For
example, if you are writing php reference lookup command, and the
cursor is on p in “ print_r($y);”, you want to grab the whole
“print_r” not just “print”. The exact meaning of symbol depends on the
mode's Syntax Table.

Reference: Elisp Manual: Syntax-Tables.

------------------------------
Here's a example of php reference lookup command that grabs by
“symbol”.

(defun php-lookup ()
"Look up current word in PHP ref site in a browser.\n
If a region is active (a phrase), lookup that phrase."
(interactive)
(let (myword myurl)
(setq myword
(if (and transient-mark-mode mark-active)
(buffer-substring-no-properties (region-beginning)
(region-end))
(thing-at-point 'symbol)))
(setq myurl
(concat "http://us.php.net/" myword))
(browse-url myurl)))
Reference: Elisp Manual: Buffer-Contents.

------------------------------
Grab Between Matching Pairs

Grab the current text between delimiters such as between angle
brackets “<>”, parens “()”, double quotes “""”, etc.

(defun select-inside-quotes ()
"Select text between double straight quotes
on each side of cursor."
(interactive)
(let (p1 p2)
(skip-chars-backward "^\"")
(setq p1 (point))
(skip-chars-forward "^\"")
(setq p2 (point))

(goto-char p1)
(push-mark p2)
(setq mark-active t)
)
)

------------------------------
Acting on Region

Idiom for a command that works on the current region.

Let your function have 2 parameters, such as “start” and “end”, then
use “(interactive "r")”, then the parameters will be filled with
beginning and ending positions of the region. Example:

(defun remove-hard-wrap-region (start end)
"Replace newline chars in region by single spaces."
(interactive "r")
(let ((fill-column 90002000))
(fill-region start end)))

------------------------------
Idiom for acting on the region, if there's one, else, on the current
word or thing.

(defun down-case-word-or-region ()
"Make current word or region into lower case."
(interactive)
(let (pos1 pos2)
(if (and transient-mark-mode mark-active)
(setq pos1 (region-beginning)
pos2 (region-end))
(setq pos1 (car (bounds-of-thing-at-point 'word))
pos2 (cdr (bounds-of-thing-at-point 'word))))
(downcase-region pos1 pos2)
)
)

------------------------------
Prompting and Getting Input

Idiom for promping user for input as the argument to your command.

Use this code “(interactive "‹code›‹promp string›")”. Example:

(defun query-friends-phone (name)
"..."
(interactive "sEnter friend's name: ")
(message "Name: %%s" name)
)

What the “(interactive "sEnter friend's name:")” does is that it will
ask user to input something, taken as string, and becomes the value of
your command's parameter.

The “interactive” can be used to get other types of input. Here are
some basic examples of using “interactive”.

“(interactive)” makes the function available thru interactive use,
where user can call it with execute-extended-command (M-x).

“(interactive "s")” will prompt the user to enter a argument, taken as
string, as argument to the function.

“(interactive "n")” will prompt the user to enter a argument, taken as
number, as argument to the function.

The prompt text can follow the single-letter code string.

If your function takes multiple inputs, you can promp user multiple
times, using a single call “interactive”, by joining the promp code
string with “\n” in between, like this:

(defun query-friends-phone (name age)
"..."
(interactive "sEnter friend's name: \nnEnter friend's age: ")
(message "Name: %%s, Age: %%d" name age)
)

Reference: Elisp Manual: Defining-Commands.

------------------------------
Batch Style Text Processing Idioms

Open a file, process it, save, close it

; open a file, process it, save, close it
(defun my-process-file (fpath)
"process the file at fullpath fpath ..."
(let (mybuffer)
(setq mybuffer (find-file fpath))
(goto-char (point-min)) ;; in case buffer already open
;; do something
(save-buffer)
(kill-buffer mybuffer)))

For processing hundreds of files, you don't need emacs to keep undo
info or fontification. This is more efficient:

(defun my-process-file (fpath)
"process the file at fullpath fpath ..."
(let ()
;; create temp buffer without undo record. first space is
necessary
(set-buffer (get-buffer-create " myTemp"))
(insert-file-contents filePath nil nil nil t)
;; process it ...
(kill-buffer " myTemp")))

------------------------------
Find Replace strings:

; idiom for string replacement in current buffer;
; use search-forward-regexp if you need regexp
(goto-char (point-min))
(while (search-forward "myStr1" nil t) (replace-match
"myReplaceStr2"))
(goto-char (point-min))
(while (search-forward "myStr2" nil t) (replace-match
"myReplaceStr2"))
;; repeat for other strings ...

Calling a shell command.

; idiom for calling a shell command
(shell-command "cp /somepath/myfile.txt /somepath")

; idiom for calling a shell command and get its output
(shell-command-to-string "ls")
Both shell-command and shell-command-to-string will wait for the shell
process to finish before continuing. To not wait, use start-process or
start-process-shell-command.

Reference: Elisp Manual: Asynchronous-Processes.

------------------------------
Traverse a directory recursively.

In the following, my-process-file is a function that takes a file full
path as input. The find-lisp-find-files will generate a list of full
paths, using a regex on file name. The “mapc” will apply the function
to elements in a list.

; idiom for traversing a directory
(require 'find-lisp)
(mapc 'my-process-file (find-lisp-find-files "~/web/emacs/" "\\.html
$"))

------------------------------

Xah
http://xahlee.org/

6 Comments
diggit! del.icio.us! reddit!

RELATED THREADS
SubjectArticles qty Group
Re: .emacs in the Windows version of Emacsgnu.emacs.help ·