ElispCookbook

Last edit

Added:

> A file-tree-walk function has been added to the Emacs development tree. Until it lands in your version, you can use this:


This page contains snippets of code that demonstrate basic EmacsLisp programming operations in the spirit of the O’Reilly cookbook series of books. For every task addressed, a worked-out solution is presented as a short, focused, directly usable piece of code.

All this stuff can be found elsewhere, but it is scattered about in libraries, manuals, etc. It would be helpful to have here in one spot.

These recipes should be pastable into the *scratch* buffer so that users can hit ‘C-j’ and evaluate them step by step.

There’s going to be some overlap with CategoryCode, obviously. Just link to more elaborate pages when appropriate. Should this page grow too large, we’ll split it up later.

Strings

The empty string (zero-length string, null string, …):

    (zerop (string-match "" "")) ;; O(n)
    ==> t
    (string-equal "" "") ;; O(n)?
    ==> t
    (equal "" "") ;; O(n)?
    ==> t
    (zerop (length "")) ;; O(1)
    ==> t

As a (very minor) space and performance optimization, starting with Emacs 23, Emacs keeps an interned copy of the empty string as a single object

    (eq "" "") ;; O(1)
    ==> t ; nil prior to Emacs 23
    (eq "" (purecopy ""))
    ==> t ; nil prior to Emacs 23
    (eq "" (propertize "" 'face 'italic))
    ==> t ; nil prior to Emacs 23

Strings vs buffer text

While it is quite common in other programming languages to work on strings contained in variables, in Emacs it is also common to work on text in buffers.

Substrings

    (substring "abcdefg" 0 3)
    ==> "abc"
    (substring "abcdefg" -3 -1)
    ==> "ef"

The TO argument is optional:

    (substring "abcdefg" -3)
    ==> "efg"

Buffers:

    (with-temp-buffer (insert "abcdefg") (buffer-substring 2 4))
    ==> "bc"

starts-with and ends-with predicates

    (defun string/ends-with (s ending)
      "Return non-nil if string S ends with ENDING."
      (cond ((>= (length s) (length ending))
             (let ((elength (length ending)))
               (string= (substring s (- 0 elength)) ending)))
            (t nil)))
    (defun string/starts-with (s begins)
      "Return non-nil if string S starts with BEGINS."
      (cond ((>= (length s) (length begins))
             (string-equal (substring s 0 (length begins)) begins))
            (t nil)))

Faster, simpler:

    (defun string/ends-with (string suffix)
      "Return t if STRING ends with SUFFIX."
      (and (string-match (rx-to-string `(: ,suffix eos) t)
                         string)
           t))
    (defun string/starts-with (string prefix)
      "Return t if STRING starts with prefix."
      (and (string-match (rx-to-string `(: bos ,prefix) t)
                         string)
           t))

Processing characters

Reversing a string:

    (defun string/reverse (str)
      "Reverse the str where str is a string"
      (apply #'string 
	     (reverse 
	      (string-to-list str))))

See CharacterProcessing and StringModification. See tr for an example mixing strings and characters.

Looking at characters in a temporary buffer:

    (with-temp-buffer
      (insert "abcdefg")
      (goto-char (point-min))
      (while (not (= (char-after) ?b)) (forward-char))
      (point))
    ==> 2

Trim whitespace

Trim whitespace from the end of a string:

    (setq test-str "abcdefg  ")
    (when (string-match "[ \t]*$" test-str)
      (message (concat "[" (replace-match "" nil nil test-str) "]")))

Trim whitespace from a string with a Perl-like chomp function:

    (defun chomp (str)
      "Chomp leading and tailing whitespace from STR."
      (while (string-match "\\`\n+\\|^\\s-+\\|\\s-+$\\|\n+\\'"
                           str)
        (setq str (replace-match "" t t str)))
      str)

Let’s not overcomplicate matters:

    (defun chomp-end (str)
      "Chomp tailing whitespace from STR."
      (replace-regexp-in-string (rx (* (any " \t\n")) eos)
                                ""
                                str))
    (defun chomp (str)
      "Chomp leading and tailing whitespace from STR."
      (replace-regexp-in-string (rx (or (: bos (* (any " \t\n")))
                                        (: (* (any " \t\n")) eos)))
                                ""
                                str))

Splitting strings

See SplitString.

Joining strings

Use ‘mapconcat’ to join a list of strings using a separator string between them.

Example:

  (mapconcat 'identity '("" "home" "alex " "elisp" "erc") "/")
    ==> "/home/alex /elisp/erc"

Serialization

Convert forms to strings using ‘prin1-to-string’, then convert back from a string using ‘read’.

  (length (read (prin1-to-string (make-list 1000000 '(x)))))
    ==> 1000000
  (read (prin1-to-string "Hello World!"))
    ==> "Hello World!"

This works only in the simplest cases. Unfortunately, it doesn’t work for all EmacsLisp data types.

  (read (prin1-to-string (make-hash-table))) ;; Error before Emacs 23.
    ==> #s(hash-table size 65 test eql rehash-size 1.5 [...] data ())
  (read (prin1-to-string (current-buffer)))
    ==> Lisp error: (invalid-read-syntax "#")

Formatting

Killing text

As the ElispManual says, “Most of the kill commands are primarily for interactive use […] When you need to delete text for internal purposes within a Lisp function, you should normally use deletion functions, so as not to disturb the kill ring contents.”

The following mimic the ‘kill-’ commands but without disturbing the kill ring. To make them kill, use ‘kill-region’ instead of ‘delete-region’.

Delete region

The Lisp equivalent of ‘kill-region’ (‘C-w’) but without kill-ring side effects::

  (delete-region (region-beginning) (region-end))

According to the ElispManual, “Few programs need to use the ‘region-beginning’ and ‘region-end’ functions.” This is because Lisp code should not rely on nor “alter the mark unless altering the mark is part of the user-level functionality of the command. (And, in that case, this effect should be documented.) To remember a location for internal use in the Lisp program, store it in a Lisp variable. For example: […]”

Delete line

The equivalent of ‘kill-line’ (‘C-k’) but without kill-ring side effects:

 (let ((beg (point)))
   (forward-line 1)
   (forward-char -1)
   (delete-region beg (point)))

Alternatively, replacing the ‘let’ with ‘progn’.

  (delete-region (point) (progn (forward-line 1)
                                (forward-char -1)
                                (point)))

Or just: (delete-region (point) (line-end-position))

The examples with ‘forward-line’ are shown for comparison with other examples, below.

Delete line backwards

The equivalent of killing the line backwards (‘C-0 C-k’) but without kill-ring side effects:

 (let ((beg (point)))
   (forward-line 0)
   (delete-region (point) beg))

Alternatively, replacing the ‘let’ with ‘progn’.

  (delete-region (progn (forward-line 0) (point))
                 (point))

Or just: (delete-region (line-beginning-position) (point))

Delete line to next line

The equivalent of killing the line and the newline (‘C-1 C-k’) but without kill-ring side effects:

 (let ((beg (point)))
   (forward-line 1)
   (delete-region beg (point)))

Alternatively, replacing the ‘let’ with ‘progn’.

  (delete-region (point) (progn (forward-line 1) (point)))

Delete whole line

The equivalent of ‘kill-whole-line’ (‘C-S-DEL’) but without kill-ring side effects:

 (let ((beg (progn (forward-line 0)
                   (point))))
   (forward-line 1)
   (delete-region beg (point)))

Alternatively, replacing the ‘let’ with ‘progn’.

  (delete-region (progn (forward-line 0) (point))
                 (progn (forward-line 1) (point)))

Or just:

  (delete-region (line-beginning-position)
                 (line-end-position))

Delete word

The equivalent of ‘kill-word’ (‘M-d’) but without kill-ring side effects:

 (let ((beg (point)))
   (forward-word 1)
   (delete-region beg (point)))

Alternatively, replacing the ‘let’ with ‘progn’.

  (delete-region (point) (progn (forward-word 1) (point)))

Delete sentence

The equivalent of ‘kill-sentence’ (‘M-k’) but without kill-ring side effects:

 (let ((beg (point)))
   (forward-sentence 1)
   (delete-region beg (point)))

Alternatively, replacing the ‘let’ with ‘progn’.

  (delete-region (point) (save-excursion
                           (forward-sentence 1)
                           (point)))

Numbers

Test whether a string represents a number

 (defun string-integer-p (string)
   (if (string-match "\\`[-+]?[0-9]+\\'" string)
       t
     nil))
 (string-integer-p "1234")
   ==> t
 (string-integer-p "x1234")
   ==> nil
 (string-integer-p "3.141592653589793")
   ==> nil
 (defun string-float-p (string)
   (if (string-match "\\`[-+]?[0-9]+\\.[0-9]*\\'" string)
       t
     nil))
 (string-float-p "1234")
   ==> nil
 (string-float-p "3.141592653589793")
   ==> t
 (string-float-p ".1")
   ==> nil
 (string-float-p "1.")
   ==> t

String to number

The following example is for instruction. Normally standard function ‘string-to-number’ would be used.

  (defun decimal-number (string)
    (let ((n (string-to-number string)))
      (save-match-data
        (if (and (not (zerop n))
                 (string-match "\\`\\s-*0+\\.?0*\\s-*\\'" string))
            n
          nil))))
  
  (decimal-number "536870911")
  ==> 536870911
  
  (decimal-number "536870912")
  ==> 536870912.0
  
  (decimal-number "3.141592653589793")
  ==> 3.141592653589793
  
  (decimal-number "042")
  ==> 42
  
  (decimal-number " 0 ")
  ==> 0
  
  (decimal-number "000")
  ==> 0
  
  (decimal-number "0.0")
  ==> 0.0

Random numbers

  (random 2)  ;coin toss (0 or 1)
  (+ (random 6) 1)  ;dice

Put commas in numbers

  (defun group-number (num &optional size char)
    "Format NUM as string grouped to SIZE with CHAR."
    ;; Based on code for `math-group-float' in calc-ext.el
    (let* ((size (or size 3))
           (char (or char ","))
           (str (if (stringp num)
                    num
                  (number-to-string num)))
            ;; omitting any trailing non-digit chars
            ;; NOTE: Calc supports BASE up to 36 (26 letters and 10 digits ;)
           (pt (or (string-match "[^0-9a-zA-Z]" str) (length str))))
      (while (> pt size)
        (setq str (concat (substring str 0 (- pt size))
                          char
                          (substring str (- pt size)))
              pt (- pt size)))
      str))
  (group-number 299792458)
  ==> "299,792,458"
  (group-number "149597870691" 4 " ")
  ==> "1495 9787 0691"

Increment numbers

See IncrementNumber.

Dates and times

Today's date

  (defun today-is ()
    "Display current time."
    (interactive)
    (message (format-time-string "Today is %Y-%m-%d %T")))

See InsertingTodaysDate.

Formatting dates

Use the function ‘format-time-string’ which is a build in function in both Emacsen and works like ‘strftime’:

    ;; Year-Month-Day:
    (insert (format-time-string "%Y-%m-%d"))
    ;; Hour:Minutes:Seconds
    (insert (format-time-string "%H-%M-%S"))

Conversions

Read a date from a string.

  (let ((time (date-to-time "Tue, 27-Sep-83 12:35:59 EST")))
    (set-time-zone-rule t) ;; Use Universal time.
    (prog1 (format-time-string "%Y-%m-%d %T UTC" time)
      (set-time-zone-rule nil))) ;; Reset to default time zone.
  ==> "1983-09-27 17:35:59 UTC"

Decode a time object.

  (decode-time (date-to-time "Tue, 27-Sep-83 12:35:59 EST"))
  ==> (59 35 13 27 9 1983 2 t -14400)

Get the seconds from the unix epoch.

  (let ((time (date-to-time "13 Feb 2009 23:31:30 UTC")))
    (float-time time))
  ==> 1234585890.0

Find the date for seconds from the unix epoch.

  (format-time-string "%Y-%m-%d %T UTC" (seconds-to-time 1234585890))
  ==> "2009-02-13 23:31:30 UTC"

Find the date 30 seconds in the future.

  (format-time-string "%Y-%m-%d %T UTC" (time-add (current-time)
                                                  (seconds-to-time 30)))
  ==> "2012-02-13 10:07:11 UTC"

Formatting elapsed time in years, days, hours, minutes and seconds.

  (format-seconds "%Y %D %h:%m:%s" (1- (* 367 24 3600)))
  ==> "1 year 1 day 23:59:59"

Find the days between two dates.

  (let ((days1 (time-to-days (date-to-time "Tue, 27-Sep-83 12:35:59 EST")))
        (days2 (time-to-days (date-to-time "2009-02-13 23:31:30 UTC"))))
    (- days2 days1))
  ==> 9271

Getting the day in the year.

  (time-to-day-in-year (current-time))
  ==> 44

Build a date based on the day of the year.

  (format-time-string "%j"
                      (encode-time 0 0 0 44 1 2012))
  ==> "044"

Pattern matching

“Patterns” refers to RegularExpressions.

There’s a set of functions that work in strings, and a set that work in buffers.

Finding

    (string-match "foo*" "Fight foo for food!")
    ==> 6

Using a temporary buffer instead:

    (with-temp-buffer
      (insert "Fight foo for food!")
      (goto-char (point-min))
      (re-search-forward "foo*")
      (point))
    ==> 10

Alternative without regular expressions: ‘search-forward’.

The functions working on buffers move point to the end of the occurrence found and return it. That’s why the result is 10 instead of 6.

Verifying

Sometimes you just want to check whether you’re at the right place:

    (with-temp-buffer
      (insert "Fight foo for food!")
      (goto-char (point-min))
      (looking-at "fight"))
    ==> t

Search and replace

    (replace-regexp-in-string "foo*" "fu" "Fight foo for food!")
    ==> "Fight fu fur fud!"

Using a temporary buffer instead:

    (with-temp-buffer
       (insert "Fight foo for food!")
       (goto-char (point-min))
       (while (re-search-forward "foo*" nil t)
         (replace-match "fu"))
       (buffer-string))
    ==> "Fight fu fur fud!"

Alternative without regular expressions: ‘search-forward’.

See also StringSearchAndReplace.

Search and do something with match

This finds numbers and increments them by one. It depends on ‘decimal-number’ that was defined above. See also IncrementNumber.

  (while (re-search-forward "[0-9]" nil t)
    (goto-char (match-beginning 0))
    (when (and (looking-at "[-+]?[0-9]+\\.?[0-9]*")
               (decimal-number (match-string 0)))
      (replace-match
       (number-to-string (1+ (string-to-number (match-string 0)))))
      (goto-char (match-end 0))))

This loads EmacsLisp files listed one per line in a text file.

  (with-current-buffer (find-file-noselect "~/load-files.txt")
    (while (re-search-forward "^.*\\.el\\(\\.gz\\)?$" nil t)
      (let ((filename (match-string 0)))
        (when (file-exists-p filename)
          (load-file filename)))))

Extracting submatches from a regex match

Like in most other regex implementations, if you use grouping parentheses in a regular expression, you can extract the text that matched each parenthesized group. Groups are numbered from the opening parenthesis, left to right. These are also called back references, or backrefs, or matching groups.

    (save-match-data ; is usually a good idea
      (and (string-match "\\`\\([^@]+\\)@\\([^@]+\\)\\'" email)
           (setq user (match-string 1 email)
                 domain (match-string 2 email) ) ))

Usually you would use *let* instead of *setq* but this is just a simple self-contained example. See also DynamicBindingVsLexicalBinding.

Mapping with a regex

This invokes a function at every match of a regexp:

   (defun map-regex (buffer regex fn)
     "Map the REGEX over the BUFFER executing FN.

   FN is called with the match-data of the regex.

   Returns the results of the FN as a list."
     (with-current-buffer buffer
       (save-excursion
         (goto-char (point-min))
         (let (res)
           (save-match-data
             (while (re-search-forward regex nil t)
               (let ((f (match-data)))
                 (setq res
                       (append res
                               (list
                                (save-match-data
                                  (funcall fn f))))))))
           res))))

An example use might be:

    (map-regex
     (find-file-noselect "~/work/elnode-auth/build-parts.txt")
     "^\\(.*.el\\(\\.gz\\)*\\)$"
     (lambda (md)
       (let ((filename (match-string 0)))
         (when (file-exists-p filename)
           (load-file filename))))))

Finding all the strings that match

If you want to list all the matching strings, including subexpressions:

  (defun match-strings-all (&optional string)
    "Return the list of all expressions matched in last search.
  
  STRING is optionally what was given to `string-match'."
    (let ((n-matches (1- (/ (length (match-data)) 2))))
      (mapcar (lambda (i) (match-string i string))
              (number-sequence 0 n-matches))))

Here’s an example:

    (let ((str "time help"))
      (string-match "time \\([A-Za-z]+\\)$" str)
      (match-strings-all str))
    ==> ("time help" "help")

Code Comments

Move to the beginning of the current comment:

    (require 'newcomment)
    (comment-beginning)

Move to the text after a comment:

    (comment-search-forward (line-end-position) t)

See also EndOfLineNoComments.

Sequences

Datatypes used to represent sequences of things:

     _____________________________________________
    |                                             |
    |          Sequence                           |
    |  ______   ________________________________  |
    | |      | |                                | |
    | | List | |             Array              | |
    | |      | |    ________       ________     | |
    | |______| |   |        |     |        |    | |
    |          |   | Vector |     | String |    | |
    |          |   |________|     |________|    | |
    |          |  ____________   _____________  | |
    |          | |            | |             | | |
    |          | | Char-table | | Bool-vector | | |
    |          | |____________| |_____________| | |
    |          |________________________________| |
    |_____________________________________________|

Lists

List basics are explained at ListStructure. Lists can shrink and grow, but access to elements towards the end of the list is slow if the list is long.

Use ‘cons’, ‘push’, or ‘add-to-list’ to prepend a new element to a list. Use ‘nth’ to access an element of a list.

    (let ((words '("fight" "foo" "for" "food!")))
      (when (string= "foo" (nth 1 words))
        (setq words (cons "bar" words)))
      words)
    ==> ("bar" "fight" "foo" "for" "food!")

See ListModification for more ways of changing a list.

Iteration:

    (let ((result  ()))
      (dolist (word  '("fight" "foo" "for" "food!"))
        (when (string-match "o" word) (push word result)))
      (nreverse result))
    ==> ("foo" "for" "food!")

Note how ‘push’ adds an element to the front of the list, so that usually the list has to be reversed after the loop. ‘nreverse’ is particularly efficient because it does this destructively. See DestructiveOperations for more about this.

Copying:

Use ‘copy-sequence’ to make a shallow copy of a list without changing the original.

    (let* ((orig '((1 2) (3 4)))
           (copy (copy-sequence orig)))
      (setcdr copy '((5 6)))
      (list orig copy))
    ==> (((1 2) (3 4)) ((1 2) (5 6)))

The elements in the copy remain in the original. More importantly, they are in fact the same elements (i.e., ‘eq’), not copies. The list is copied, but its elements are shared with the original list.

    (let* ((orig '((1 2) (3 4)))
           (copy (copy-sequence orig)))
      (setcdr (cadr copy) '(0))
      (list orig copy))
    ==> (((1 2) (3 0)) ((1 2) (3 0)))

‘copy-tree’ is the recursive version of ‘copy-sequence’.

    (let* ((orig '((1 2) (3 4)))
           (copy (copy-tree orig)))
      (setcdr (cadr copy) '(0))
      (list orig copy))
    ==> (((1 2) (3 4)) ((1 2) (3 0)))

Filtering:

A ‘filter’ macro has been added to the Emacs development tree. It does what you expect: filters a list, returning a copy that keeps elements that satisfy a predicate and omitting elements that do not satisfy it.

If your Emacs does not yet have this built in, you can use ‘dolist’ or ‘mapcar’ to iterate over a list with a conditional, and then use ‘delq’ to remove the ‘nil’ values.

  (defun my-filter (condp lst)
    (delq nil
          (mapcar (lambda (x) (and (funcall condp x) x)) lst)))

Therefore,

  (my-filter 'identity my-list)

is equivalent to

  (delq nil my-list)

For example:

  (let ((num-list '(1 'a 2 "nil" 3 nil 4)))
    (my-filter 'numberp num-list))
  ==> (1 2 3 4)

Package ‘cl-seq’ has functions ‘remove-if’ and ‘remove-if-not’. The latter can be used instead of ‘my-filter’.

  (let ((num-list '(1 'a 2 "nil" 3 nil 4)))
    (remove-if-not 'numberp num-list))
  ==> (1 2 3 4)
  (let ((num-list '(1 'a 2 "nil" 3 nil 4)))
    (remove-if 'numberp num-list))
  ==> ((quote a) "nil" nil)

Here is a version of quicksort:

  (defun quicksort (lst)
    "Implement the quicksort algorithm."
    (if (null lst) nil
      (let* ((spl (car lst))
             (rst (cdr lst))
             (smalp (lambda (x)
                   (< x spl))))
        (append (quicksort (remove-if-not smalp rst))
                (list spl)
                (quicksort (remove-if smalp rst))))))
  (quicksort '(5 7 1 3 -9 8 7 -4 0))
  ==> (-9 -4 0 1 3 5 7 7 8)

The following function was written by [[tali713?]] in response to [[hypnocat?]]’s question regarding a filter function in #emacs:

    (defun keep-when (pred seq)
      (let ((del (make-symbol "del")))
        (remove del (mapcar (lambda (el)
			      (if (funcall pred el) el del)) seq))))

Use:

  (keep-when 'atom '(1 2 3 (4 5) 6 nil t foo))
  ==> (1 2 3 6 nil t foo)

Updated 31/05/2013.

Tranposing:

Create a list from multiple lists:

 ((lambda (&rest args)
    (mapcar (lambda (n)
              (delq nil (mapcar (lambda (arg) (nth n arg)) args)))
            (number-sequence 0 (1- (apply 'max (mapcar 'length args))))))
  '(1 2 3) '(a b c) '(A B C))
  ==> ((1 a A) (2 b B) (3 c C))

A more concise version is possible with the the higher-arity version of ‘mapcar’ available from library ‘cl’.

  ((lambda (&rest args)
     (apply (function mapcar*) (function list) args))
   '(1 2 3) '(a b c) '(A B C))
  ==> ((1 a A) (2 b B) (3 c C))

Searching:

You can check for presence of a value in a list using ‘member’ or ‘memq’.

  (let ((words  '("fight" "foo" "for" "food!")))
    (car (member "for" words)))
  ==> "for"
  (let ((re    "\\wo\\b")
        (words '("fight" "foo" "for" "food!")))
    (consp (memq t
             (mapcar (lambda (s) (numberp (string-match re s))) words))))
  ==> t

In the latter, a more efficient algorithm would use a loop (a non-local exit).

Association lists

The ElispManual has examples of finding and deleting values in an association list, or alist. Here are cases when the car values are strings.

  (assoc "2" '(("2" . 2) ("1" . 1) ("2") ("3" . 3)))
  ==> ("2" . 2)
  (mapcar (lambda (c) (cons c (string c))) (number-sequence 56 65))
  ==> ((56 . "8") (57 . "9") (58 . ":") (59 . ";") (60 . "<")
       (61 . "=") (62 . ">") (63 . "?") (64 . "@") (65 . "A"))
  (assq 64
        (mapcar (lambda (c) (cons c (string c))) (number-sequence 56 65)))
  ==> (64 . "@")
  (assq 55
        (mapcar (lambda (c) (cons c (string c))) (number-sequence 56 65)))
  ==> nil

Deleting:

  (let ((alist '(("a" . 1) ("b" . 2))))
    (delq (assoc "a" alist) alist))
  ==> (("b" . 2))

Matches with a test function other than ‘equal’:

  (let ((alist '(("ab" . 1) ("bc" . 2) ("cd" . 3))))
    (assoc-default "c" alist (lambda (x y) (string-match y x))))
  ==> 2

The alist functions are useful for finding the first instance of a value in any list, not just association lists, and even when there are duplicates.

The following uses ‘mapcar’ to associate the ‘major-mode’ to each buffer returned by ‘buffer-list’, then ‘assq’ to find the first buffer where the major mode is ‘fundamental-mode’.

  (assq 'fundamental-mode
        (mapcar
         (lambda (b)
           (cons (buffer-local-value 'major-mode b) b))
         (buffer-list)))
  ==> (fundamental-mode . #<buffer *Messages*>)

You can also find values in regular lists, by converting them to association lists with a null cdr.

Here’s an association list of random numbers with no associated value.

  '((8 . nil) (3 . nil) (1 . nil) (7 . nil) (3 . nil) (6 . nil) (9 . nil))
  ==> ((8) (3) (1) (7) (3) (6) (9))

This is really just making a list for each number – a “list of lists” – which can be done with ‘mapcar’ and ‘list’.

  (mapcar 'list '(8 3 1 7 3 6 9))
  ==> ((8) (3) (1) (7) (3) (6) (9))
  (assq 3 (mapcar 'list '(8 3 1 7 3 6 9)))
  ==> (3)

Vectors

Vectors are fixed in size, and their elements can be accessed in constant time (neither of which is the case for lists).

    (let ((words ["fight" "foo" "for" "food!"]))
      (when (string= "foo" (aref words 1))
        (aset words 1 "bar"))
      words)
    ==> ["fight" "bar" "for" "food!"]

Convert vector to list

All vectors are sequences and the map functions work on sequences, so:

(mapcar 'identity [1 2 3 4]) 
  ==> (1 2 3 4)

Here is another Lisp idiom for the same thing:

(append [1 2 3 4] ())
  ==> (1 2 3 4)

Hash tables

Hash tables map keys to values. They are similar to alists, but they are typically more efficient for a large number of keys.

See HashMap.

Storing and retrieving keys and values

By default, hash tables use ‘eql’ to compare keys. This is not appropriate for strings: (eql "alex" "alex") ⇒ nil. Use ‘equal’ in such cases:

    (let ((nick-table (make-hash-table :test 'equal)))
      (puthash "kensanata" "Alex Schroeder" nick-table)
      (gethash "kensanata" nick-table))
    ==> "Alex Schroeder"

Iterate:

    (let ((nick-table (make-hash-table :test 'equal))
          nicks)
      (puthash "kensanata" "Alex Schroeder" nick-table)
      (puthash "e1f" "Luis Fernandes" nick-table)
      (puthash "pjb" "Pascal J. Bourguignon" nick-table)
      (maphash (lambda (nick real-name)
                 (setq nicks (cons nick nicks)))
               nick-table)
      nicks)
      ==> ("pjb" "e1f" "kensanata")

Sorting keys

Use ‘maphash’ to build up a list of keys, sort it, and then loop through the list:

    (let ((nick-table (make-hash-table :test 'equal))
          nicks)
      (puthash "kensanata" "Alex Schroeder" nick-table)
      (puthash "e1f" "Luis Fernandes" nick-table)
      (puthash "pjb" "Pascal J. Bourguignon" nick-table)
      (maphash (lambda (nick real-name)
                 (setq nicks (cons nick nicks)))
               nick-table)
      (mapcar (lambda (nick)
                (concat nick " => " (gethash nick nick-table)))
              (sort nicks 'string<)))
      ==> ("e1f => Luis Fernandes"
           "kensanata => Alex Schroeder"
           "pjb => Pascal J. Bourguignon")

Files

Read

A file can be inserted at point with ‘insert-file-contents’ or ‘insert-file-contents-literally’. To get a file as a string,

  (defun file-string (file)
    "Read the contents of a file and return as a string."
    (with-temp-buffer
      (insert-file-contents file)
      (buffer-string)))

On the chance that a buffer may already be actively visiting the file, consider using ‘find-file-noselect’

  (defun file-string (file)
    "Read the contents of a file and return as a string."
    (with-current-buffer (find-file-noselect file)
      (buffer-string)))

Filter

Processing a file is usually done with a temporary buffer:

 (defun process-file (file)
   "Read the contents of a file into a temp buffer and then do
 something there."
   (when (file-readable-p file)
     (with-temp-buffer
       (insert-file-contents file)
       (goto-char (point-min))
       (while (not (eobp))
         ;; do something here with buffer content
         (forward-line)))))

Write

To write something to a file you can create a temporary buffer, insert the things to write there and write the buffer contents to a file. The following example read a string and a filename (with completion, but doesn’t need to exist, see InteractiveCodeChar? F) and write the string to that file.

 (defun write-string-to-file (string file)
   (interactive "sEnter the string: \nFFile to save to: ")
   (with-temp-buffer
     (insert string)
     (when (file-writable-p file)
       (write-region (point-min)
                     (point-max)
                     file))))

Another way to do this is via with-temp-file:

 (defun write-string-to-file (string file)
   (interactive "sEnter the string: \nFFile to save to: ")
   (with-temp-file file
     (insert string)))

Input and output (I/O)

This is a nice and simple way to edit a file with Emacs Lisp, especially when there’s a chance the file might be already be visited in Emacs and its ok to edit the existing buffer.

  (with-current-buffer (find-file-noselect "~/logfile")
    (goto-char (point-max))
    (insert (format "Hash of last line: %s"
             (md5
              (save-excursion
                (forward-line -1)
                (buffer-substring-no-properties (point)
                                                (line-end-position))))))
    (newline)
    (with-temp-message "Writing file..."
      (save-buffer))
    (message "Writing file...done"))

Searching within a File

If you don’t have grep, then you may need to write some Lisp which can find a match in a file.

  ;; Visit file unless its already open.
  (with-current-buffer (find-file-noselect "~/.emacs")
    (save-excursion ;; Don't change location of point.
      (goto-char (point-min)) ;; From the beginning...
      (if (re-search-forward ".*load-path.*" nil t 1)
          (match-string-no-properties 0)
        (error "Search failed"))))
  ==> "(add-to-list 'load-path \"/usr/share/emacs/site-lisp/\")"

Locking

    (unless (file-locked-p (buffer-file-name))
       (lock-buffer))

Stat

An interface to the kernel’s stat(2) is provided by the function file-attributes.

    (let* ((attrs (file-attributes (buffer-file-name)))
           (atime (nth 4 attrs))
           (mtime (nth 5 attrs))
           (ctime (nth 6 attrs)))
      (concat "File last accessed on "
              (format-time-string "%Y-%m-%d %T" atime) "\n"
              "File last modified on "
              (format-time-string "%Y-%m-%d %T" mtime) "\n"
              "File last changed on "
              (format-time-string "%Y-%m-%d %T" ctime) "\n"))

Deleting

  (if (file-exists-p filename)
      (delete-file filename))

Copy, move and rename

  (copy-file file new-name)
  (rename-file file new-dir)
  (rename-file file new-name)

Directories

Listing

All files in a directory sorted by name:

  (directory-files "~/")
  ==> ("." ".." ".bash_history" ".bashrc" ".emacs" ".emacs.d" "diary" "local" "public_html")

File names matching a regular expression and in no particular order.

  (directory-files "~/" (not 'absolute) "\\`\\." 'nosort)
  ==> (".emacs.d" ".emacs" ".bash_history" ".bashrc" ".." ".")

File names matching a wildcard expression sorted by name.

  (let ((default-directory "~/"))
    (file-expand-wildcards "?emacs*"))
  ==> (".emacs" ".emacs.d")

All files sorted by modification time:

  (let ((default-directory "~/"))
    (sort
      (directory-files default-directory (not 'absolute) nil 'nosort)
      (lambda (a b)
        (time-less-p (nth 5 (file-attributes a))
                     (nth 5 (file-attributes b))))))
  ==> (".bashrc" "diary" "public_html" "local" ".bash_history" ".." ".emacs" ".emacs.d" ".")

Recursion

Here’s an example of using ‘directory-files’ to find all subdirectories in a subdirectory.

Could potentially surpass ‘max-lisp-eval-depth’ if the filesystem has a suffienctly complex number of subdirectories.

  (defun directory-dirs (dir)
    "Find all directories in DIR."
    (unless (file-directory-p dir)
      (error "Not a directory `%s'" dir))
    (let ((dir (directory-file-name dir))
          (dirs '())
          (files (directory-files dir nil nil t)))
        (dolist (file files)
          (unless (member file '("." ".."))
            (let ((file (concat (file-name-as-directory dir) file)))
              (when (file-directory-p file)
                (setq dirs (append (cons file
                                         (directory-dirs file))
                                   dirs))))))
        dirs))

Giving ‘directory-dirs’ an absolute file name:

  (directory-dirs "/emacs/lisp")
  ==> ("/usr/share/emacs/23.2/lisp/calc" "/usr/share/emacs/23.2/lisp/calendar"
       "/usr/share/emacs/23.2/lisp/cedet" "/usr/share/emacs/23.2/lisp/cedet/ede" ...)

Setting the ‘default-directory’ to a directory allows ‘directory-dirs’ to return relative file names for subdirectories.

  (let ((default-directory "/usr/share/emacs/23.2/lisp"))
    (directory-dirs "."))
  ==> ("./calc" "./calendar" "./cedet" "./cedet/ede" ...)

Traversing

A file-tree-walk function has been added to the Emacs development tree. Until it lands in your version, you can use this:

    (defun walk-path (dir action)
       "walk DIR executing ACTION with (dir file)"
       (cond ((file-directory-p dir)
              (or (char-equal ?/ (aref dir(1- (length dir))))
                  (setq dir (file-name-as-directory dir)))
              (let ((lst (directory-files dir nil nil t))
                     fullname file)
                (while lst
                  (setq file (car lst))
                  (setq lst (cdr lst))
                  (cond ((member file '("." "..")))
                        (t
                         (and (funcall action dir file)
                              (setq fullname (concat dir file))
                              (file-directory-p fullname)
                              (walk-path fullname action)))))))
             (t
              (funcall action
                       (file-name-directory dir)
                       (file-name-nondirectory dir)))))
    (defun walk-path-visitor (dir file)
       "Called by walk-path for each file found"
       (message (concat  dir file)))
    (walk-path "~/" 'walk-path-visitor)

Path splitting

Splitting the path can be done with ‘split-string’ and with the slash. Previously, Emacs would determine the character separating directory names with ‘directory-sep-char’. However, the variable is obselete with Emacs 21.1.

  (split-string default-directory "/")
  ==> ("" "usr" "share" "emacs" "22.2" "lisp" "")

For splitting a path variable, Emacs already has the ‘parse-colon-path’ function.

  (parse-colon-path (getenv "PATH"))
  ==> ("/usr/lib/qt-3.3/bin/" "/usr/kerberos/bin/" "/usr/local/bin/" "/usr/bin/" "/bin/" "/usr/local/sbin/" "/usr/sbin/" "/sbin/")

Processes

Running a program

Run a command without caring about its output.

  (async-shell-command "emacs")

Run a command and put its output in the current buffer.

  (shell-command "seq 8 12 | sort" t)
  10
  11
  12
  8
  9

Run a command and put its output in a new buffer.

  (shell-command "seq 8 12 | sort"
                 (get-buffer-create "*Standard output*"))

Run a command return its output as a string.

  (shell-command-to-string "seq 8 12 | sort")

Run a command return and insert its output at point in the current buffer.

  (insert (shell-command-to-string "date"))

Handling signals

Sockets

Tcp client

Tcp server

Perhaps EmacsEchoServer and EmacsDaytimeServer can be useful here. Also Edit with Emacs' edit-server.el which is a more complete server implementation.

Keyboard events

Call function bound to key

  (funcall (key-binding (kbd "M-TAB")))

or

  (call-interactively (key-binding (kbd "M-TAB")))

Test code

Sometimes you might want to insert some demonstration code in a module. The code should not be run when the module is loaded via ‘require’ or ‘load’ but when you ‘eval-current-buffer’. All you need to do add is add a test condition of ‘eval-buffer-list’:

  (dont-compile
    (when (eq (car eval-buffer-list) (current-buffer))
      ...))

CategoryCode