Emacs Essentials
emacs techTable of Contents
It is a steep learning curve to master Emacs lisp, there are mainly two issues in it from my experience
- the lisp syntax and functional programming
- the fragmented methods and libraries
For the 1st issue, it is easy to master the syntax after writing several programs and getting used to them, but for the 2nd one, one needs to take notes or remember something.
In this blog, I focus on the 2nd point and keep updating the notes of some methods and libraries that I think are essential for writing Emacs lisp packages.
builtin methods
buffer
current-buffer: get the current buffer
(current-buffer)
#<buffer emacs-essentials.org>
get-buffer: get a buffer by name
(get-buffer "*scratch*")
#<buffer *scratch*>
get-buffer-create: create the buffer if not exist
(get-buffer-create "yaya")
#<buffer yaya>
changing the current buffer
(progn
(set-buffer (get-buffer "*scratch*"))
(current-buffer))
Goto a buffer
(with-current-buffer "*BUF*"
;; do something like progn
)
Changing the current buffer safely
It will return to the original buffer after the operation finished.
(progn
(save-current-buffer
(set-buffer "*scratch*")
(message "Current buffer: %s" (current-buffer)))
(current-buffer))
#<buffer 20210801162858-emacs_lisp.org>
Working with file buffers
To get the full file path for the file that the buffer represents
(buffer-file-name)
/Users/yanchunwei/project/myblog2022/content-org/emacs-essentials.org
To find a buffer that represents a particular file
(get-file-buffer "/Users/yanchunwei/project/myblog2022/content-org/emacs-essentials.org")
#<buffer emacs-essentials.org>
Loading a file into a buffer without display it
(find-file-noselect "xx.org")
Get all buffer names
(mapcar #'buffer-name (buffer-list))
save-execution: Operate on other buffers without altering the current context
Buffer is a core data structure in elisp, so it is normial to switch to other buffers, do some operations and return back. save-execution
helps to restore the previous context when switching to other buffers.
(save-excursion
(progn
;; do anything on other buffers
)
)
;; Return to the previous context: buffer and point
point
The “point” is the location of the cursor in the buffer.
(point)
7508
(point-max)
8010
(point-min)
1
Moving the point
(goto-char 1)
(goto-char (point-max))
;; goto the begining of the buffer
(beginning-of-buffer)
;; goto the end of the buffer
(end-of-buffer)
(forward-char)
(forward-char 5)
(forward-word)
(backward-word)
Preserving the point
(save-excursion
(goto-char (point-max))
(point)
)
8471
Examining buffer text
To look at text in the buffer.
(char-after)
(char-after (point))
(char-after (point-min))
58
The Thing
The thing-at-point
function is very useful for grabbing the text at the point if it matches a particular type of “thing”.
(thing-at-point 'word)
(thing-at-point 'sentence)
(thing-at-point 'sentence)
#+END_SRC
(thing-at-point 'sentence t)
(thing-at-point 'sentence t)
#+END_SRC
Serching for text
(search-forward "thing")
Inserting text
(insert "000")
(insert "\n" "This is" ?\s ?\n "Sparta!")
Deleting text
(with-current-buffer ".gitignore"
(delete-region (point) (point-max)))
Saving a buffer
To save the contents of a buffer back to the file it is associated with
(save-buffer)
org-model programming
Tags related
Tags in org-mode are as below:
* heading :tag0:tag1:
Get tags
To get tags on the current entry:
(org-get-tags)
Set tags
To set tags on the current entry:
(org-set-tags '("hello")) :hello:
Properties related
Properties in org-mode is as follows, where a property called “prop” has a “value”. It is handy to store some meta data using properties.
* headline
:PROPERTIES:
:prop: value
:END:
Get properties
Get properties of the current entry:
(org-entry-properties)
Set property
To set a property on the current entry:
(org-set-property "name" "tom")
file and path
Get the path of the current file
The buffer-file-name
is a buffer builtin variable holding the file name of the current buffer.
(file-truename buffer-file-name)
/tmp/emacs-essentials.org
Get path without suffix
(file-name-sans-extension "/tmp/a.org")
/tmp/a
Write to file
Overwrite the content:
(with-temp-file "/tmp/1.org"
(insert "hello world")
(message "file content: %s" (buffer-string))
)
file content: hello world
execute shell command
(shell-command "echo hello")
0
condition-case: try-catch in elisp
Like the try-catch in Python, where a try-catch can launch some unsafe function and catch the error.
(condition-case err
(progn
(message "No error"))
(error "some error")
)
No error
Modern libraries
ht.el for hashtables
Reference ht.el for more details.
creating a hash table
Create an empty hash table
(let* ((the-dic (ht-create)))
the-dic
)
#s(hash-table size 65 test equal rehash-size 1.5 rehash-threshold 0.8125 data ())
Create a hash table with initial records
(let* ((the-dic (ht
("name" "Tom")
("sex" 'male))))
the-dic
)
#s(hash-table size 65 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("name" "Tom" "sex" male))
accessing the hash table
(let* ((the-dic (ht ("name" "Tom") ("sex" 'male))))
;; get a record
;; returns "Tom"
(ht-get the-dic "name")
)
Tom
Iterating over the hash table
Readonly mapping:
(let* ((the-dic (ht ("name" "Tom") ("sex" 'male) ("age" 18))))
(ht-map (lambda (key value) (message "%S: %S" key value)) the-dic)
)
“age”: 18 | “sex”: male | “name”: “Tom” |
Mutable mapping:
(let* ((the-dic (ht ("name" "Tom") ("sex" 'male) ("age" 18))))
(ht-map (lambda (key value)
;; modify the value if is string
(setf value (if (stringp value)
(concat "modified " value)
value))) the-dic))
18 | male | modified Tom |
Debug and development in Elisp
One handly tool is toggle-debug-on-error
, it will print the error stack.