https://wikemacs.org/api.php?action=feedcontributions&user=195.8.70.202&feedformat=atom
WikEmacs - User contributions [en]
2024-03-28T13:06:24Z
User contributions
MediaWiki 1.35.14
https://wikemacs.org/index.php?title=Emacs_Lisp_Cookbook&diff=2838
Emacs Lisp Cookbook
2012-05-21T12:37:19Z
<p>195.8.70.202: /* Get today's date */ added to Elisp Cookbook</p>
<hr />
<div>This page contains snippets of code that demonstrate basic [[Emacs Lisp]]<br />
programming operations in the spirit of O'Reilly's Cookbook<br />
series of books. For every task addressed, a worked-out solution<br />
is presented as a short, focused, directly usable piece of code.<br />
<br />
All this stuff can be found elsewhere, but it is scattered about in<br />
libraries, manuals, etc. It would be helpful to have it here in one<br />
spot.<br />
<br />
These recipes should be pastable into the '''*scratch*''' buffer so that<br />
users can hit '''C-j''' and evaluate them step by step.<br />
<br />
== Strings ==<br />
<br />
The empty string (zero-length string, null string, ...):<br />
<br />
<syntaxhighlight lang="lisp"><br />
(zerop (string-match "" "")) ;; O(n)<br />
==> t<br />
<br />
(string-equal "" "") ;; O(n)?<br />
==> t<br />
<br />
(equal "" "") ;; O(n)?<br />
==> t<br />
<br />
(zerop (length "")) ;; O(1)<br />
==> t<br />
<br />
(eq "" "") ;; O(1)<br />
==> t<br />
</syntaxhighlight><br />
<br />
As a space and performance optimization, Emacs keeps an intern-ed copy<br />
of the empty string as a single object<br />
<br />
<syntaxhighlight lang="lisp"><br />
(eq "" (purecopy ""))<br />
==> t<br />
<br />
(eq "" (propertize "" 'face 'italic))<br />
==> t<br />
</syntaxhighlight><br />
<br />
=== Strings vs buffer content ===<br />
<br />
While it is quite common in other programming languages to work on<br />
strings contained in variables in Emacs it is even more idiomatic to<br />
work on strings in buffers. That's why the following contains examples<br />
of both.<br />
<br />
=== Substrings ===<br />
<br />
<syntaxhighlight lang="lisp"><br />
(substring "abcdefg" 0 3)<br />
==> "abc"<br />
(substring "abcdefg" -3 -1)<br />
==> "ef"<br />
</syntaxhighlight><br />
<br />
The TO argument is optional:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(substring "abcdefg" -3)<br />
==> "efg"<br />
</syntaxhighlight><br />
<br />
Buffers:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(with-temp-buffer<br />
(insert "abcdefg")<br />
(buffer-substring 2 4))<br />
==> "bc"<br />
</syntaxhighlight><br />
<br />
=== Processing characters ===<br />
<br />
Reversing a string:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(string-to-list "foo")<br />
==> (102 111 111)<br />
(reverse (string-to-list "foo"))<br />
==> (111 111 102)<br />
(apply 'string (reverse (string-to-list "foo")))<br />
==> "oof"<br />
</syntaxhighlight><br />
<br />
See CharacterProcessing and StringModification. See [[tr]] for an example of you sometimes need to mix strings and characters.<br />
<br />
Looking at characters in buffers:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(with-temp-buffer<br />
(insert "abcdefg")<br />
(goto-char (point-min))<br />
(while (not (= (char-after) ?b))<br />
(forward-char))<br />
(point))<br />
==> 2<br />
</syntaxhighlight><br />
<br />
=== Trim whitespace ===<br />
<br />
Trim whitespace from the end of a string:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(setq test-str "abcdefg ")<br />
(when (string-match "[ \t]*$" test-str)<br />
(message (concat "[" (replace-match "" nil nil test-str) "]")))<br />
</syntaxhighlight><br />
<br />
Trim whitespace from a string with a Perl-like chomp function:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(defun chomp (str)<br />
"Chomp leading and tailing whitespace from STR."<br />
(while (string-match "\\`\n+\\|^\\s-+\\|\\s-+$\\|\n+\\'"<br />
str)<br />
(setq str (replace-match "" t t str)))<br />
str)<br />
</syntaxhighlight><br />
<br />
=== Splitting strings ===<br />
<br />
TODO<br />
<br />
=== Joining strings ===<br />
<br />
Use `mapconcat' to join a list into a string using a separator ("glue") between elements in the string.<br />
<br />
Example:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(mapconcat 'identity '("" "home" "alex " "elisp" "erc") "/")<br />
==> "/home/alex /elisp/erc"<br />
</syntaxhighlight><br />
<br />
=== Serialization ===<br />
<br />
The basic idea is to convert forms to strings with `prin1-to-string' and convert it back from a string with `read'.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(length (read (prin1-to-string (make-list 1000000 '(x)))))<br />
==> 1000000<br />
<br />
(read (prin1-to-string "Hello World!"))<br />
==> "Hello World!"<br />
</syntaxhighlight><br />
<br />
This only works in the simplest cases. Unfortunately, this doesn't work for all Emacs data types for programming or the editor.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(read (prin1-to-string (make-hash-table))) ;; Error before Emacs 23.<br />
==> #s(hash-table size 65 test eql rehash-size 1.5 [...] data ())<br />
<br />
(read (prin1-to-string (current-buffer)))<br />
==> Lisp error: (invalid-read-syntax "#")<br />
</syntaxhighlight><br />
<br />
=== Formatting ===<br />
<br />
== Killing text ==<br />
<br />
As the Emacs Lisp Manual says, "Most of the kill commands are primarily for<br />
interactive use [...] When you need to delete text for internal<br />
purposes within a Lisp function, you should normally use deletion<br />
functions, so as not to disturb the kill ring contents."<br />
<br />
The following mimic the `kill-' commands but without disturbing the kill ring.<br />
<br />
=== Delete region ===<br />
<br />
The Lisp equivalent of `kill-region' (`C-w') but without kill ring side effects::<br />
<br />
<syntaxhighlight lang="lisp"><br />
(delete-region (region-beginning) (region-end))<br />
</syntaxhighlight> <br />
<br />
According to the ElispManual, "Few programs need to use the<br />
`region-beginning' and `region-end' functions." This is because<br />
Lisp code should not rely on nor "alter the mark unless altering<br />
the mark is part of the user-level functionality of the<br />
command. (And, in that case, this effect should be documented.)<br />
To remember a location for internal use in the Lisp program,<br />
store it in a Lisp variable. For example: [...]"<br />
<br />
<syntaxhighlight lang="lisp"><br />
(let ((beg (point)))<br />
(forward-line 1)<br />
(delete-region beg (point)))<br />
</syntaxhighlight><br />
<br />
=== Delete line ===<br />
<br />
The equivalent of `kill-line' (`C-k') but without kill ring side effects:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(let ((beg (point)))<br />
(forward-line 1)<br />
(forward-char -1)<br />
(delete-region beg (point)))<br />
</syntaxhighlight><br />
<br />
Alternatively, replacing the `let' with `save-excursion'.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(delete-region (point)<br />
(save-excursion<br />
(forward-line 1)<br />
(forward-char -1)<br />
(point)))<br />
</syntaxhighlight> <br />
<br />
Or simplest of all,<br />
<br />
<syntaxhighlight lang="lisp"><br />
(delete-region (point) (line-end-position))<br />
</syntaxhighlight> <br />
<br />
The examples with `forward-line' are shown because the paradigm is used later, see below.<br />
<br />
=== Delete line backwards ===<br />
<br />
The equivalent of killing the line backwards (`C-0 C-k') but without kill ring side effects:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(let ((beg (point)))<br />
(forward-line 0)<br />
(delete-region (point) beg))<br />
</syntaxhighlight> <br />
<br />
Alternatively, replacing the `let' with `save-excursion'.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(delete-region (save-excursion<br />
(forward-line 0)<br />
(point))<br />
(point))<br />
</syntaxhighlight> <br />
<br />
Or simplest of all,<br />
<br />
<syntaxhighlight lang="lisp"><br />
(delete-region (line-beginning-position) (point))<br />
</syntaxhighlight> <br />
<br />
<br />
=== Delete line to next line ===<br />
<br />
The equivalent of killing the line and the newline (`C-1 C-k') but without kill ring side effects:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(let ((beg (point)))<br />
(forward-line 1)<br />
(delete-region beg (point)))<br />
</syntaxhighlight> <br />
<br />
Alternatively, replacing the `let' with `save-excursion'.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(delete-region (point)<br />
(save-excursion<br />
(forward-line 1)<br />
(point)))<br />
</syntaxhighlight> <br />
<br />
=== Delete whole line ===<br />
<br />
The equivalent of `kill-whole-line' (`C-S-DEL') but without kill ring side effects:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(let ((beg (progn (forward-line 0)<br />
(point))))<br />
(forward-line 1)<br />
(delete-region beg (point)))<br />
</syntaxhighlight> <br />
<br />
Alternatively, replacing the `let' with `save-excursion'.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(delete-region (save-excursion<br />
(forward-line 0)<br />
(point))<br />
(save-excursion<br />
(forward-line 1)<br />
(point)))<br />
</syntaxhighlight> <br />
<br />
Or simplest of all,<br />
<br />
<syntaxhighlight lang="lisp"><br />
(delete-region (line-beginning-position) (line-end-position))<br />
</syntaxhighlight> <br />
<br />
=== Delete word ===<br />
<br />
The equivalent of `kill-word' (`M-d') but without kill ring side effects:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(let ((beg (point)))<br />
(forward-word 1)<br />
(delete-region beg (point)))<br />
</syntaxhighlight> <br />
<br />
Alternatively, replacing the `let' with `save-excursion'.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(delete-region (point)<br />
(save-excursion<br />
(forward-word 1)<br />
(point)))<br />
</syntaxhighlight> <br />
<br />
=== Delete sentence ===<br />
<br />
The equivalent of `kill-sentence' (`M-k') but without kill ring side effects:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(let ((beg (point)))<br />
(forward-sentence 1)<br />
(delete-region beg (point)))<br />
</syntaxhighlight> <br />
<br />
Alternatively, replacing the `let' with `save-excursion'.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(delete-region (point)<br />
(save-excursion<br />
(forward-sentence 1)<br />
(point)))<br />
</syntaxhighlight><br />
<br />
== Numbers ==<br />
<br />
=== String a number? ===<br />
<br />
<syntaxhighlight lang="lisp"><br />
(defun string-integer-p (string)<br />
(if (string-match "\\`[-+]?[0-9]+\\'" string)<br />
t<br />
nil))<br />
<br />
(string-integer-p "1234")<br />
==> t<br />
<br />
(string-integer-p "x1234")<br />
==> nil<br />
<br />
(string-integer-p "3.141592653589793")<br />
==> nil<br />
<br />
(defun string-float-p (string)<br />
(if (string-match "\\`[-+]?[0-9]+\\.[0-9]*\\'" string)<br />
t<br />
nil))<br />
<br />
(string-float-p "1234")<br />
==> nil<br />
<br />
(string-float-p "3.141592653589793")<br />
==> t<br />
<br />
(string-float-p ".1")<br />
==> nil<br />
<br />
(string-float-p "1.")<br />
==> t<br />
</syntaxhighlight> <br />
<br />
=== String to number ===<br />
<br />
<syntaxhighlight lang="lisp"><br />
(defun decimal-number (string)<br />
(let ((n (string-to-number string)))<br />
(if (and (zerop n)<br />
(not (string-match "\\`\\s-*0+\\.?0*\\s-*\\'" string)))<br />
nil<br />
n)))<br />
<br />
(decimal-number "536870911")<br />
==> 536870911<br />
<br />
(decimal-number "536870912")<br />
==> 536870912.0<br />
<br />
(decimal-number "3.141592653589793")<br />
==> 3.141592653589793<br />
<br />
(decimal-number "042")<br />
==> 42<br />
<br />
(decimal-number " 0 ")<br />
==> 0<br />
<br />
(decimal-number "000")<br />
==> 0<br />
<br />
(decimal-number "0.0")<br />
==> 0.0<br />
</syntaxhighlight> <br />
<br />
<br />
=== Random numbers ===<br />
<br />
<syntaxhighlight lang="lisp"><br />
(random 2) ;coin toss (0 or 1)<br />
(+ (random 6) 1) ;dice<br />
</syntaxhighlight> <br />
<br />
=== Put commas in numbers ===<br />
<br />
<syntaxhighlight lang="lisp"><br />
(defun group-number (num &optional size char)<br />
"Format NUM as string grouped to SIZE with CHAR."<br />
;; Based on code for `math-group-float' in calc-ext.el<br />
(let* ((size (or size 3))<br />
(char (or char ","))<br />
(str (if (stringp num)<br />
num<br />
(number-to-string num)))<br />
(pt (or (string-match "[^0-9a-zA-Z]" str) (length str))))<br />
(while (> pt size)<br />
(setq str (concat (substring str 0 (- pt size))<br />
char<br />
(substring str (- pt size)))<br />
pt (- pt size)))<br />
str))<br />
<br />
(group-number 299792458)<br />
==> "299,792,458"<br />
(group-number "149597870691" 4 " ")<br />
==> "1495 9787 0691"<br />
</syntaxhighlight> <br />
<br />
=== Incrementing numbers ===<br />
<br />
TODO<br />
<br />
== Dates and times ==<br />
<br />
=== Get today's date ===<br />
<br />
<syntaxhighlight lang="lisp"><br />
(format-time-string "%d %B %Y")<br />
</syntaxhighlight><br />
<br />
or <br />
<br />
<syntaxhighlight lang="lisp"><br />
(eshell/date)<br />
</syntaxhighlight><br />
<br />
=== Formatting dates ===<br />
<br />
Use the function `format-time-string' which is a build in function in both Emacsen and works like `strftime':<br />
<br />
<syntaxhighlight lang="lisp"><br />
;; Year-Month-Day:<br />
(insert (format-time-string "%Y-%m-%d"))<br />
;; Hour:Minutes:Seconds<br />
(insert (format-time-string "%H-%M-%S"))<br />
</syntaxhighlight> <br />
<br />
=== Conversions ===<br />
<br />
Read a date from a string.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(let ((time (date-to-time "Tue, 27-Sep-83 12:35:59 EST")))<br />
(set-time-zone-rule t) ;; Use Universal time.<br />
(prog1 (format-time-string "%Y-%m-%d %T UTC" time)<br />
(set-time-zone-rule nil))) ;; Reset to default time zone.<br />
==> "1983-09-27 17:35:59 UTC"<br />
</syntaxhighlight> <br />
<br />
Decode a time object.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(decode-time (date-to-time "Tue, 27-Sep-83 12:35:59 EST"))<br />
==> (59 35 13 27 9 1983 2 t -14400)<br />
</syntaxhighlight> <br />
<br />
Get the seconds from the unix epoch.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(let ((time (date-to-time "13 Feb 2009 23:31:30 UTC")))<br />
(float-time time))<br />
==> 1234585890.0<br />
</syntaxhighlight> <br />
<br />
Find the date for seconds from the unix epoch.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(format-time-string "%Y-%m-%d %T UTC" (seconds-to-time 1234585890))<br />
==> "2009-02-13 23:31:30 UTC"<br />
</syntaxhighlight> <br />
<br />
Find the date 30 seconds in the future.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(format-time-string "%Y-%m-%d %T UTC" (time-add (current-time)<br />
(seconds-to-time 30)))<br />
==> "2012-02-13 10:07:11 UTC"<br />
</syntaxhighlight> <br />
<br />
Formatting elapsed time in years, days, hours, minutes and seconds.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(format-seconds "%Y %D %h:%m:%s" (1- (* 367 24 3600)))<br />
==> "1 year 1 day 23:59:59"<br />
</syntaxhighlight> <br />
<br />
Find the days between two dates.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(let ((days1 (time-to-days (date-to-time "Tue, 27-Sep-83 12:35:59 EST")))<br />
(days2 (time-to-days (date-to-time "2009-02-13 23:31:30 UTC"))))<br />
(- days2 days1))<br />
==> 9271<br />
</syntaxhighlight> <br />
<br />
Getting the day in the year.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(time-to-day-in-year (current-time))<br />
==> 44<br />
</syntaxhighlight> <br />
<br />
Build a date based on the day of the year.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(format-time-string "%j"<br />
(encode-time 0 0 0 44 1 2012))<br />
==> "044"<br />
</syntaxhighlight> <br />
<br />
=== Timers ===<br />
<br />
TODO<br />
<br />
== Pattern matching ==<br />
<br />
"Patterns" refers to RegularExpression""s.<br />
<br />
There's a set of functions that work in strings, and a set that work in buffers.<br />
<br />
=== Finding ===<br />
<br />
<syntaxhighlight lang="lisp"><br />
(string-match "foo*" "Fight foo for food!")<br />
==> 6<br />
</syntaxhighlight> <br />
<br />
Buffers:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(with-temp-buffer<br />
(insert "Fight foo for food!")<br />
(goto-char (point-min))<br />
(re-search-forward "foo*")<br />
(point))<br />
==> 10<br />
</syntaxhighlight> <br />
<br />
Alternative without regular expressions: `search-forward'.<br />
<br />
Note that the functions working on buffers move point to the end of the occurrence found and return it.<br />
That's why the result is 10 instead of 6!<br />
<br />
=== Comments ===<br />
<br />
Move to the beginning of the current comment:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(require 'newcomment)<br />
(comment-beginning)<br />
</syntaxhighlight> <br />
<br />
Move to the text after a comment:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(comment-search-forward (line-end-position) t)<br />
</syntaxhighlight> <br />
<br />
See also EndOfLineNoComments.<br />
<br />
=== Search and replace ===<br />
<br />
<syntaxhighlight lang="lisp"><br />
(replace-regexp-in-string "foo*" "fu" "Fight foo for food!")<br />
==> "Fight fu fur fud!"<br />
</syntaxhighlight> <br />
<br />
Buffers:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(with-temp-buffer<br />
(insert "Fight foo for food!")<br />
(goto-char (point-min))<br />
(while (re-search-forward "foo*" nil t)<br />
(replace-match "fu"))<br />
(buffer-string))<br />
==> "Fight fu fur fud!"<br />
</syntaxhighlight> <br />
<br />
Alternative without regular expressions: `search-forward'.<br />
<br />
See also StringSearchAndReplace.<br />
<br />
=== Verifying ===<br />
<br />
Sometimes you just want to check whether you're at the right place:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(with-temp-buffer<br />
(insert "Fight foo for food!")<br />
(goto-char (point-min))<br />
(looking-at "fight"))<br />
==> t<br />
</syntaxhighlight> <br />
<br />
== Sequences ==<br />
<br />
Datatypes used to represent sequences of things:<br />
<br />
_____________________________________________<br />
| |<br />
| Sequence |<br />
| ______ ________________________________ |<br />
| | | | | |<br />
| | List | | Array | |<br />
| | | | ________ ________ | |<br />
| |______| | | | | | | |<br />
| | | Vector | | String | | |<br />
| | |________| |________| | |<br />
| | ____________ _____________ | |<br />
| | | | | | | |<br />
| | | Char-table | | Bool-vector | | |<br />
| | |____________| |_____________| | |<br />
| |________________________________| |<br />
|_____________________________________________|<br />
<br />
<br />
=== Lists ===<br />
<br />
List basics are explained on ListStructure.<br />
Lists can shrink and grow, but access to elements towards the end of the list is slow if the list is long.<br />
<br />
Use `cons' to append a new element to the front of a list.<br />
Use `nth' to access an element of the list.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(let ((words '("fight" "foo" "for" "food!")))<br />
(when (string= "foo" (nth 1 words))<br />
(setq words (cons "bar" words)))<br />
words)<br />
==> ("bar" "fight" "foo" "for" "food!")<br />
</syntaxhighlight> <br />
<br />
See ListModification for more ways of changing a list.<br />
<br />
Iteration:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(let ((result))<br />
(dolist (word '("fight" "foo" "for" "food!"))<br />
(when (string-match "o" word)<br />
(setq result (cons word result))))<br />
(nreverse result))<br />
==> ("foo" "for" "food!")<br />
</syntaxhighlight> <br />
<br />
Note how `cons' adds an element to the front of the list,<br />
so that usually the list has to be reversed after the loop.<br />
`nreverse' is particularly efficient because it does this<br />
destructively by swiveling pointers around. See<br />
DestructiveOperations for more about this.<br />
<br />
Copying:<br />
<br />
Use `copy-sequence' to make a copy of a list that won't change the<br />
elements of the original.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(let* ((orig '((1 2) (3 4)))<br />
(copy (copy-sequence orig)))<br />
(setcdr copy '((5 6)))<br />
(list orig copy))<br />
==> (((1 2) (3 4)) ((1 2) (5 6)))<br />
</syntaxhighlight> <br />
<br />
However, the elements in the copy are still from the original.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(let* ((orig '((1 2) (3 4)))<br />
(copy (copy-sequence orig)))<br />
(setcdr (cadr copy) '(0))<br />
(list orig copy))<br />
==> (((1 2) (3 0)) ((1 2) (3 0)))<br />
</syntaxhighlight> <br />
<br />
The function `copy-tree' is the recursive version of `copy-sequence'.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(let* ((orig '((1 2) (3 4)))<br />
(copy (copy-tree orig)))<br />
(setcdr (cadr copy) '(0))<br />
(list orig copy))<br />
==> (((1 2) (3 4)) ((1 2) (3 0)))<br />
</syntaxhighlight> <br />
<br />
Filtering:<br />
<br />
Emacs Lisp doesn't come with a `filter' function to keep elements that satisfy a conditional and excise the elements that do not satisfy it. One can use `mapcar' to iterate over a list with a conditional, and then use `delq' to remove the `nil' values.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(defun my-filter (condp lst)<br />
(delq nil<br />
(mapcar (lambda (x) (and (funcall condp x) x)) lst)))<br />
</syntaxhighlight> <br />
<br />
Therefore,<br />
<br />
<syntaxhighlight lang="lisp"><br />
(my-filter 'identity my-list)<br />
</syntaxhighlight> <br />
<br />
is equivalent to<br />
<br />
<syntaxhighlight lang="lisp"><br />
(delq nil my-list)<br />
</syntaxhighlight> <br />
<br />
For example:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(let ((num-list '(1 'a 2 "nil" 3 nil 4)))<br />
(my-filter 'numberp num-list))<br />
==> (1 2 3 4)<br />
</syntaxhighlight> <br />
<br />
Actually the package cl-seq contains the functions `remove-if' and `remove-if-not'. The latter can be used instead of `my-filter'.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(let ((num-list '(1 'a 2 "nil" 3 nil 4)))<br />
(remove-if-not 'numberp num-list))<br />
==> (1 2 3 4)<br />
<br />
(let ((num-list '(1 'a 2 "nil" 3 nil 4)))<br />
(remove-if 'numberp num-list))<br />
==> ((quote a) "nil" nil)<br />
</syntaxhighlight> <br />
<br />
As an example here is the quick sort algorithm:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(defun quicksort (lst)<br />
"Implement the quicksort algorithm."<br />
(if (null lst) nil<br />
(let* ((spl (car lst))<br />
(rst (cdr lst))<br />
(smalp (lambda (x)<br />
(< x spl))))<br />
(append (quicksort (remove-if-not smalp rst))<br />
(list spl)<br />
(quicksort (remove-if smalp rst))))))<br />
<br />
(quicksort '(5 7 1 3 -9 8 7 -4 0))<br />
==> (-9 -4 0 1 3 5 7 7 8)<br />
</syntaxhighlight> <br />
<br />
Tranposing:<br />
<br />
Convert multiple lists into a list <br />
<br />
<syntaxhighlight lang="lisp"><br />
((lambda (&rest args)<br />
(mapcar (lambda (n)<br />
(delq nil (mapcar (lambda (arg) (nth n arg)) args)))<br />
(number-sequence 0 (1- (apply 'max (mapcar 'length args))))))<br />
'(1 2 3) '(a b c) '(A B C))<br />
==> ((1 a A) (2 b B) (3 c C))<br />
</syntaxhighlight> <br />
<br />
A more concise version is possible with the the higher-arity version of mapcar available with the `cl' library.<br />
<br />
<syntaxhighlight lang="lisp"><br />
((lambda (&rest args)<br />
(apply (function mapcar*) (function list) args))<br />
'(1 2 3) '(a b c) '(A B C))<br />
==> ((1 a A) (2 b B) (3 c C))<br />
</syntaxhighlight> <br />
<br />
Searching:<br />
<br />
Simply checking for existence of a value in a list can be done with<br />
`member' or `memq'.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(let ((words '("fight" "foo" "for" "food!")))<br />
(car (member "for" words)))<br />
==> "for"<br />
<br />
(let ((re "\\wo\\b")<br />
(words '("fight" "foo" "for" "food!")))<br />
(consp (memq t<br />
(mapcar (lambda (s) (numberp (string-match re s))) words))))<br />
==> t<br />
</syntaxhighlight> <br />
<br />
In the latter, a more efficient algorithm would use a loop (a non-local exit).<br />
<br />
=== Association lists ===<br />
<br />
The ElispManual has examples of finding and deleting values in an<br />
association list. Here are cases when the car values are strings.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(assoc "2" '(("2" . 2) ("1" . 1) ("2") ("3" . 3)))<br />
==> ("2" . 2)<br />
</syntaxhighlight> <br />
<br />
Deleting:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(let ((alist '(("a" . 1) ("b" . 2))))<br />
(delq (assoc "a" alist) alist))<br />
==> (("b" . 2))<br />
</syntaxhighlight> <br />
<br />
Matches with a test function other than `equal':<br />
<br />
<syntaxhighlight lang="lisp"><br />
(let ((alist '(("ab" . 1) ("bc" . 2) ("cd" . 3))))<br />
(assoc-default "c" alist (lambda (x y) (string-match y x))))<br />
==> 2<br />
</syntaxhighlight> <br />
<br />
=== Vectors ===<br />
<br />
Vectors are fixed in size but elements can be accessed in constant time.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(let ((words ["fight" "foo" "for" "food!"]))<br />
(when (string= "foo" (aref words 1))<br />
(aset words 1 "bar"))<br />
words)<br />
==> ["fight" "bar" "for" "food!"]<br />
</syntaxhighlight> <br />
<br />
== Hashes ==<br />
<br />
Hashes map keys to values. In a way they are similar to alists, except<br />
they are more efficient for a large number of keys.<br />
<br />
More info is available on the HashMap page.<br />
<br />
=== Storing and retrieving keys and values ===<br />
<br />
By default, hash tables use `eql' to compare keys. This is not appropriate<br />
for strings: ##(eql "alex" "alex")## ==> nil. Thus, use `equal' in these cases:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(let ((nick-table (make-hash-table :test 'equal)))<br />
(puthash "kensanata" "Alex Schroeder" nick-table)<br />
(gethash "kensanata" nick-table))<br />
==> "Alex Schroeder"<br />
</syntaxhighlight> <br />
<br />
Iterate:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(let ((nick-table (make-hash-table :test 'equal))<br />
nicks)<br />
(puthash "kensanata" "Alex Schroeder" nick-table)<br />
(puthash "e1f" "Luis Fernandes" nick-table)<br />
(puthash "pjb" "Pascal J. Bourguignon" nick-table)<br />
(maphash (lambda (nick real-name)<br />
(setq nicks (cons nick nicks)))<br />
nick-table)<br />
nicks)<br />
==> ("pjb" "e1f" "kensanata")<br />
</syntaxhighlight> <br />
<br />
=== Sorting keys ===<br />
<br />
Use `maphash' to build up a list of keys, sort it, and then loop through<br />
the list:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(let ((nick-table (make-hash-table :test 'equal))<br />
nicks)<br />
(puthash "kensanata" "Alex Schroeder" nick-table)<br />
(puthash "e1f" "Luis Fernandes" nick-table)<br />
(puthash "pjb" "Pascal J. Bourguignon" nick-table)<br />
(maphash (lambda (nick real-name)<br />
(setq nicks (cons nick nicks)))<br />
nick-table)<br />
(mapcar (lambda (nick)<br />
(concat nick " => " (gethash nick nick-table)))<br />
(sort nicks 'string<)))<br />
==> ("e1f => Luis Fernandes"<br />
"kensanata => Alex Schroeder"<br />
"pjb => Pascal J. Bourguignon")<br />
</syntaxhighlight> <br />
<br />
== Files ==<br />
<br />
=== Read ===<br />
<br />
Processing a file is usually done with a temporary buffer:<br />
<br />
<syntaxhighlight lang="lisp"><br />
(defun process-file (file)<br />
"Read the contents of a file into a temp buffer and then do<br />
something there."<br />
(when (file-readable-p file)<br />
(with-temp-buffer<br />
(insert-file-contents file)<br />
(goto-char (point-min))<br />
(while (not (eobp))<br />
;; do something here with buffer content<br />
(forward-line)))))<br />
</syntaxhighlight> <br />
<br />
On the chance that a buffer may already be actively visiting the file,<br />
consider using `find-file-noselect'<br />
<br />
<syntaxhighlight lang="lisp"><br />
(defun file-string (file)<br />
"Read the contents of a file and return as a string."<br />
(with-current-buffer (find-file-noselect file)<br />
(buffer-string)))<br />
</syntaxhighlight> <br />
<br />
=== Write ===<br />
<br />
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.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(defun write-string-to-file (string file)<br />
(interactive "sEnter the string: \nFFile to save to: ")<br />
(with-temp-buffer<br />
(insert string)<br />
(when (file-writable-p file)<br />
(write-region (point-min)<br />
(point-max)<br />
file))))<br />
</syntaxhighlight> <br />
<br />
=== Input and output (I/O) ===<br />
<br />
This is a nice and simple way to edit a file with Emacs Lisp,<br />
especially when there's a chance the file might be already be visited<br />
in Emacs and its ok to edit the existing buffer.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(with-current-buffer (find-file-noselect "~/logfile")<br />
(goto-char (point-max))<br />
(insert (format "Hash of last line: %s"<br />
(md5<br />
(save-excursion<br />
(forward-line -1)<br />
(buffer-substring-no-properties (point)<br />
(line-end-position))))))<br />
(newline)<br />
(with-temp-message "Writing file..."<br />
(save-buffer))<br />
(message "Writing file...done"))<br />
</syntaxhighlight> <br />
<br />
=== Searching ===<br />
<br />
If you don't have grep, then you may need to write some Lisp which can find a match in a file.<br />
<br />
<syntaxhighlight lang="lisp"><br />
;; Visit file unless its already open.<br />
(with-current-buffer (find-file-noselect "~/.emacs")<br />
(save-excursion ;; Don't change location of point.<br />
(goto-char (point-min)) ;; From the beginning...<br />
(if (re-search-forward ".*load-path.*" nil t 1)<br />
(match-string-no-properties 0)<br />
(error "Search failed"))))<br />
==> "(add-to-list 'load-path \"/usr/share/emacs/site-lisp/\")"<br />
</syntaxhighlight> <br />
<br />
=== Filter ===<br />
<br />
=== Locking ===<br />
<br />
=== Stat ===<br />
<br />
An interface to the kernel's stat(2) is provided by the function file-attributes. The way times are represented may be a bit unexpected, though.<br />
<br />
=== Deleting ===<br />
<br />
<syntaxhighlight lang="lisp"><br />
(if (file-exists-p filename)<br />
(delete-file filename))<br />
</syntaxhighlight> <br />
<br />
=== Copy, move and rename ===<br />
<br />
== Directories ==<br />
<br />
=== Traversing ===<br />
<br />
<syntaxhighlight lang="lisp"><br />
(defun walk-path (dir action)<br />
"walk DIR executing ACTION with (dir file)"<br />
(cond ((file-directory-p dir)<br />
(or (char-equal ?/ (aref dir(1- (length dir))))<br />
(setq dir (file-name-as-directory dir)))<br />
(let ((lst (directory-files dir nil nil t))<br />
fullname file)<br />
(while lst<br />
(setq file (car lst))<br />
(setq lst (cdr lst))<br />
(cond ((member file '("." "..")))<br />
(t<br />
(and (funcall action dir file)<br />
(setq fullname (concat dir file))<br />
(file-directory-p fullname)<br />
(walk-path fullname action)))))))<br />
(t<br />
(funcall action<br />
(file-name-directory dir)<br />
(file-name-nondirectory dir)))))<br />
<br />
(defun walk-path-visitor (dir file)<br />
"Called by walk-path for each file found"<br />
(message (concat dir file)))<br />
<br />
(walk-path "~/" 'walk-path-visitor)<br />
</syntaxhighlight> <br />
<br />
=== Path splitting ===<br />
<br />
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.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(split-string default-directory "/")<br />
==> ("" "usr" "share" "emacs" "22.2" "lisp" "")<br />
</syntaxhighlight><br />
<br />
For splitting a path variable, Emacs already has the `parse-colon-path' function.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(parse-colon-path (getenv "PATH"))<br />
==> ("/usr/lib/qt-3.3/bin/" "/usr/kerberos/bin/" "/usr/local/bin/"<br />
"/usr/bin/" "/bin/" "/usr/local/sbin/" "/usr/sbin/" "/sbin/")<br />
</syntaxhighlight><br />
<br />
== Processes ==<br />
<br />
=== Running a program ===<br />
<br />
Run a command without caring about its output.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(async-shell-command "emacs")<br />
</syntaxhighlight> <br />
<br />
Run a command and put its output in the current buffer.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(shell-command "seq 8 12 | sort" t)<br />
10<br />
11<br />
12<br />
8<br />
9<br />
</syntaxhighlight> <br />
<br />
Run a command and put its output in a new buffer.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(shell-command "seq 8 12 | sort"<br />
(get-buffer-create "*Standard output*"))<br />
</syntaxhighlight> <br />
<br />
Run a command return its output as a string.<br />
<br />
<syntaxhighlight lang="lisp"><br />
(shell-command-to-string "seq 8 12 | sort")<br />
</syntaxhighlight> <br />
<br />
XEmacs also comes with `exec-to-string'.<br />
<br />
=== Handling signals ===<br />
<br />
== Sockets ==<br />
<br />
=== Tcp client ===<br />
<br />
=== Tcp server ===<br />
<br />
Perhaps EmacsEchoServer and EmacsDaytimeServer can be useful here.<br />
<br />
== Keyboard events ==<br />
<br />
* Call function bound to key<br />
<br />
<syntaxhighlight lang="lisp"><br />
(funcall (key-binding (kbd "M-TAB")))<br />
</syntaxhighlight> <br />
<br />
or<br />
<br />
<syntaxhighlight lang="lisp"><br />
(call-interactively (key-binding (kbd "M-TAB")))<br />
</syntaxhighlight> <br />
<br />
[[Category:Customization]]<br />
[[Category:Intermediate]]</div>
195.8.70.202