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.
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
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.
(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"
(defun string/ends-with (s ending) "return non-nil if string S ends with ENDING." (let ((elength (length ending))) (string= (substring s (- 0 elength)) ending)))
(defun string/starts-with (s arg) "returns non-nil if string S starts with ARG. Else nil." (cond ((>= (length s) (length arg)) (string-equal (substring s 0 (length arg)) arg)) (t nil)))
Reversing a string:
(string-to-list "foo") ==> (102 111 111) (reverse (string-to-list "foo")) ==> (111 111 102) (apply #'string (reverse (string-to-list "foo"))) ==> "oof"
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 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)
See SplitString.
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"
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 "#")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’.
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: […]”
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.
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))
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)))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))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)))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)))(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.")
==> tThe 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 2) ;coin toss (0 or 1) (+ (random 6) 1) ;dice
(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))) (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"
See IncrementNumber.
(defun today-is () "Display current time." (interactive) (message (format-time-string "Today is %Y-%m-%d %T")))
See InsertingTodaysDate.
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"))
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"
“Patterns” refers to RegularExpressions.
There’s a set of functions that work in strings, and a set that work in buffers.
(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.
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
(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.
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)))))
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.
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))))))
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")
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.
Datatypes used to represent sequences of things:
_____________________________________________
| |
| Sequence |
| ______ ________________________________ |
| | | | | |
| | List | | Array | |
| | | | ________ ________ | |
| |______| | | | | | | |
| | | Vector | | String | | |
| | |________| |________| | |
| | ____________ _____________ | |
| | | | | | | |
| | | Char-table | | Bool-vector | | |
| | |____________| |_____________| | |
| |________________________________| |
|_____________________________________________|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:
EmacsLisp doesn’t come with a ‘filter’ function to keep elements that satisfy a conditional and remove elements that do not satisfy it. 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).
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 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!"]
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 map keys to values. They are similar to alists, but they are typically more efficient for a large number of keys.
See HashMap.
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")
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")
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)))
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)))))
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)))
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"))
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/\")"
(unless (file-locked-p (buffer-file-name))
(lock-buffer))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"))
(if (file-exists-p filename)
(delete-file filename))(copy-file file new-name)
(rename-file file new-dir)
(rename-file file new-name)
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" ".")
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 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" ...)
(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)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/")
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
9Run 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"))Perhaps EmacsEchoServer and EmacsDaytimeServer can be useful here. Also Edit with Emacs' edit-server.el which is a more complete server implementation.
Call function bound to key
(funcall (key-binding (kbd "M-TAB")))or
(call-interactively (key-binding (kbd "M-TAB")))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))
...))