目录
老骥伏枥,志在千里。(曹操)
光标和选区
API (C-h f 查看函数,这里仅常用格式) | 说明 | 示例(在括号后 C-x C-e 尝试) |
---|---|---|
获取光标位置 | ||
(point) | 获取光标位置 | (point) |
(point-min) | buffer 开始位置 | (point-min) |
(point-max) | buffer 结束位置 | (point-max) |
(point-at-bol) | 行首 | (point-at-bol) |
(point-at-eol) | 行尾 | (point-at-eol) |
(region-beginning) | 选区开始位置 | (region-beginning) |
(region-end) | 选区结束位置 | (regin-end) |
(push-mark &optional LOCATION) | 设定选区,光标到指定位置 | (push-mark 10000) |
(kill-region BEGIN END) | 剪切选区 | (kill-region 1 (point)) |
(use-region-p) | 是否有活动选区 | (use-region-p) |
mark-active | 变量,是否有活动选区(高亮的选区) | (print mark-active) |
光标位置获取文本 | ||
(buffer-substring-no-properties START END) | 获取纯文本 | (buffer-substring-no-properties 10 100) |
(char-before) | 光标之前字符 | (char-before) |
(char-after) | 光标之后字符 | (char-after) |
(current-word) | 光标下的单词 | (current-word) |
(thing-at-point THING) | 光标下的元素(按参数指定) | (thing-at-point 'word) |
移动光标 | ||
(goto-char POSTION) | 移动光标到给定位置 | (goto-char 800) |
(forward-char &optional N) | 向之后移动光标, 默认移动 1 个字符 | (forward-char 3) |
(backward-char &optional N) | 向之前移动光标,默认移动 1 个字符 | (backward-char 3) |
(beginning-of-line &optional N) | 移动光标到行首,默认本行,或之前 N-1 行首 | (beginning-of-line) |
(end-of-line &optional N) | 移动光标到行尾,默认本行,或之后 N-1 行首 | (end-of-line 2) |
(next-line) | 移动光标垂直向下一行 | (next-line) |
(previous-line) | 移动光标垂直向上一行 | (previous-line) |
(forward-line &optional N) | 向之后移动光标 N 行,停在行首 | (forward-line 2) |
(line-move-visual N) | 向之后垂直移动光标 N 行 | (line-move-visual 2) |
搜索并移动光标 | ||
(search-forward STRING) | 向之后搜索,光标停在匹配文本后 | (search-forward "sea") |
(search-backward STRING) | 向之前搜索,光标停在匹配文本前 | (search-backward "sea") |
(re-search-forward REGEXP) | 用正则向之后搜索,光标停在匹配文本后 | (re-search-forward "\n") |
(re-search-backward REGEXP) | 用正则向之前搜索,光标停在匹配文本前 | (re-search-backward "\n") |
(skip-chars-forward STRING) | 往之后移动光标,跳过给定字符集合,停在匹配之后 | (skip-chars-forward "\n\t\s") |
(skip-chars-forward STRING) | 往之前移动光标,跳过给定字符集合,停在匹配之前 | (skip-chars-backward "abc") |
保存状态 | ||
(save-excursion &rest BODY) | 执行 BODY 后恢复光标原位置 | (save-excursion (insert "test")) |
(save-restriction &rest BODY) | 执行 BODY 后,保存恢复用户操作 | (save-restriction (narrow-to-region 1 100) (insert "$$$")) |
文本编辑
API | 说明 | 示例 |
---|---|---|
插入文本 | ||
(insert &rest ARGS) | 光标下插入文本 | (insert "hello" "weifeng") |
删除文本 | ||
(delete-char N) | 删除 N 个字符 | (delete-char 3) |
(delete-region START END) | 删除给定选区 | (delete-region 100 105) |
(erase-buffer) | 清空 buffer 内容 | (erase-buffer) |
(delete-and-extract-region START END) | 删除给定选区,返回被删除内容 | (delete-and-extract-region 100 105) |
剪切、复制、粘贴、替换 | ||
(kill-region BEG END) | 剪切文本到 kill-ring(粘贴环,可连续取) | (kill-region 1 100) |
(copy-region-as-kill BEG END) | 拷贝到 kill-ring | (copy-region-as-kill 1 100) |
(kill-new STRING) | 将文本放入 kill-ring | (kill-new "fengweifeng.com") |
(yank) | 粘贴到光标处 | (yank) |
(replace-match STRING) | 先查找,在替换成字符串 | (while (search-forward "AAA" nil t) (replace-match "BBB")) |
数字
说明 | demo | 值 |
---|---|---|
二进制 | #b100 | 4 |
字符串
API | 说明 | 示例 |
---|---|---|
(length STRING) | 字符串长度 | (length "abcd") |
(substring STRING START END) | 取子字符串 | (substring "abcd" 1 3) |
(concat &rest SEQ ) | 合并多个字符串 | (concat "abc" "def" "xyz") |
正则查找、替换 | ||
(string-match REGEXP STRING) | 查找匹配位置 | (string-match "\\([A-Z]+\\):\\([0-9]+\\)" "~TEL:123456") |
(match-string NUM &optional STRING) | 返回上次正则匹配第 NUM 项 | (match-string 1 "~TEL:123456") |
(replace-regexp-in-string REGEXP REPLACE STRING) | 替换 | (replace-regexp-in-string "[0-9]" "*" "pass:123") |
(split-string STRING &optional) | 切分字符串,默认以空白字符分隔 | (split-string "hi-wei-feng" "-") |
字符和数字转换 | ||
(string-to-number STRING) | 字符串转数字 | (string-to-number "123") |
(number-to-string NUM) | 数字转字符串 | (number-to-string 123) |
(format STRING &rest OBJECTS) | 使用格式化 | (format "%d" 123) |
大小写 (require 's) | ||
s-upcase(str) | 变大写 | (s-upcase "feng") |
s-downcase(str) | 变小写 | (s-downcase "FENG") |
使用 subr-x 库字符串函数:(require 'subr-x) | ||
(string-blank-p STRING) | 是否空白字符串 | (string-blank-p " ") |
(string-empty-p STRING) | 是否空字符串 | (string-empty-p " ") |
(string-join STRINGS &optional SEP) | 合并字符串 | (string-join '("a" "b" "c") "-") |
(string-reverse STRING) | 反转字符串 | (string-reverse "abc") |
(string-trim STRING) | 两头去空白 | (string-trim " abc ") |
(string-trim-left STRING) | 去除左侧空白 | (string-trim-left " abc ") |
(string-trim-right STRING) | 去除右侧空白 | (string-trim-right " abc ") |
(string-remove-prefix PREFIX STRING) | 去除头部 | (string-remove-prefix "hi" "hifeng") |
(string-remove-suffix SUFFIX STRING) | 去除尾部 | (string-remove-suffix "wf" "fengwf") |
Buffer
API | 说明 | 示例 |
---|---|---|
属性 | ||
(buffer-name &optional BUFFER) | 获取 buffer 名字 | (buffer-name) |
(buffer-file-name &optional BUFFER) | 获取 buffer 文件名 | (buffer-file-name) |
(buffer-string) | 获取 buffer 全部内容 | (buffer-string) |
(buffer-size) | buffer 字符数 | |
(buffer-hash) | buffer hash 值 | (buffer-hash) |
(bufferp) | 是否是 buffer | (list (bufferp "*scratch*") (bufferp (get-buffer "*scratch*"))) |
(buffer-modified-p) | buffer 是否被修改过 | (buffer-modified-p) |
(buffer-narrowed-p) | buffer 是否被局部显示 | |
(buffer-list) | buffer 列表 | (length (buffer-list)) |
操作 | ||
(with-current-buffer BUFFER-OR-NAME &rest BODY) | 设置要操作的 buffer | (with-current-buffer (current-buffer) (insert "ABC")) |
(set-buffer BUFFER-OR-NAME) | 设置要操作的 buffer | (with-current-buffer (current-buffer) (set-buffer "*Messages*")) |
(with-temp-buffer &rest BODY) | 创建临时 buffer | (with-temp-buffer (insert "ABC") (message (buffer-string))) |
(generate-new-buffer NAME) | 创建带名称的 buffer | (generate-new-buffer "*feng*") |
(get-buffer BUFFER-OR-NAME) | 获取已有 buffer | (get-buffer "*scratch*") |
(get-buffer-create BUFFER-OR-NAME) | 获取已有或创建 buffer | (setq buffer (get-buffer-create "*feng*")) |
(kill-buffer &optional BUFFER-OR-NAME) | 关闭当前或指定 buffer | (kill-buffer "*feng*") |
(buffer-live-p BUFFER) | buffer 是否已被关闭 | (buffer-live-p (get-buffer-create "*feng*")) |
Demo | 示例 |
---|---|
(buffer-substring-no-properties (region-beginning) (region-end)) | 选区文本 |
(buffer-substring-no-properties (line-beginning-position) (line-end-position)) | 当前行文本 |
(thing-at-point 'filename) | 光标下文件名 |
(mapcar #'thing-at-point '(symbol list sexp defun filename url email uuid word sentence whitespace line number page)) | 光标下各种元素 |
文件操作
API | 说明 | 示例 |
---|---|---|
打开、新建、保存文件 | ||
(find-file FILENAME) | 打开或新建文件 | (find-file "~/test.txt") |
(save-buffer) | 保存文件 | (save-buffer) |
(write-region START END FILENAME) | 保存部分区域到文件 | (write-region (point-min) (point-max) "~/test.txt") |
(write-file FILENAME) | 另存为 | (write-file "~/test2.txt") |
(append-to-file START END FILENAME) | 追加文件 | (append-to-file 100 200 "~/test.txt") |
文件操作 | ||
(rename-file FILENAME NEW-FILENAME) | 文件改名 | (rename-file "~/test.txt" "~/test2.txt") |
(copy-file FILENAME NEW-FILENAME) | 复制文件 | (copy-file "~/test2.txt" "~/test.txt") |
(delete-file FILENAME) | 删除文件 | (delete-file "~/test.txt") |
(set-file-modes) | 设置文件属性 | (set-file-modes "~/test.txt" #o755) |
(file-modes FILENAME) | 读取文件属性 | (file-modes "~/test.txt") |
(file-exists-p FILENAME) | 文件是否存在 | (file-exists-p "~/test.txt") |
(file-readable-p FILENAME) | 文件是否可读 | |
(file-writable-p FILENAME) | 文件是否可写 | |
(file-executable-p FILENAME) | 文件是否可运行 | |
目录操作 | ||
(directory-files DIR &optional FULL MATCH) | 获取目录文件列表,可筛选 | (directory-files "~/" t "\\.txt") |
(make-directory DIR) | 创建目录 | (make-directory "~/xxx") |
(delete-directory DIR &optional RECURSIVE TRASH) | 删除空目录,可选递归删除、进垃圾桶 | (delete-directory "~/xxx") |
(copy-directory DIR NEW-NAME) | 拷贝目录 | (copy-directory "~/xxx" "~/yyy") |
路径 | ||
(file-name-directory FILENAME) | 获取目录路径 | (file-name-directory "~/xxx") |
(file-name-nondirectory FILENAME) | 获取文件名 | (file-name-nondirectory "~/xxx") |
(file-name-extension FILENAME) | 获取后缀名 | (file-name-extension "~/test.txt") |
(file-name-sans-extension FILENAME) | 获取不含后缀名的路径 | (file-name-sans-extension "~/test.txt") |
(file-relative-name FILENAME &optional DIR) | 获取相对当前路径的路径 | (file-relative-name "~/test.txt") |
(expand-file-name NAME &optional DIR) | 基于路径展开文件路径 | (expand-file-name "test.txt") |
default-directory | 变量,当前路径 | (print default-directory) |
让用户输入
API | 说明 | demo |
---|---|---|
(read-file-name PROMPT) | 让用户输入文件 | (read-file-name "输入文件地址: ") |
(read-directory-name PROMPT) | 让用户输入目录 | (read-directory-name "输入文件夹: ") |
(read-string PROMPT) | 让用户输入文本 | (read-string "输入名称:") |
(read-regexp PROMPT) | 让用户输入正则 | (read-regexp "输入正则:") |
(read-number PROMPT) | 让用户输入数字 | (read-number "输入数字:") |
(ido-completing-read PROMPT LIST) | 让用户选择一项 | (ido-completing-read "选择:" '("A" "B" "C")) |
(y-or-n-p PROMPT) | 让用户确认是/否 | (y-or-n-p "请确认?") |
list、vector、sequence
List、Vector、字符串都被称为 Sequence。
seq-
开头的函数可用于处理这些类型变量。
-
list 长度可变,可头部插入,或从头部删除,访问元素速度得看和头部距离,如长度为 1000,则访问第 900 个元素则很慢;
-
vector 长度固定,访问任一元素耗时一样,都很快;
List 说明 | Demo |
---|---|
列表变量 | (setq a '("a" "b" "c" "d")) |
创建列表 | (list 1 2 3) |
按个数创建并设置初值 | (make-list 4 0) |
创建序列 | (number-sequence 5 10) |
打印列表 | (message "%S" a) |
空列表等于 nil | (eq '() nil) |
获取元素 | |
---|---|
获取首项 | (car a) |
获取最后一项 | (car (last a)) |
获取指定序号项 | (nth 2 a) |
列表长度 | (length a) |
获取子列表 | |
---|---|
从第二个到最后 | (cdr a) |
指定序号到最后 | (nthcdr 2 a) |
去除尾部多项 | (butlast a 2) |
合并排序 | |
---|---|
头部合并(不修改原值) | (cons "Hi" a) |
遍历操作返回结果 | (mapcar 'upcase a) |
遍历操作返回原列表 | (mapc 'print a) |
排序 | (seq-sort #'< '(1 3 2)) |
修改列表 | |
---|---|
删除元素(有副作用) | (delete "b" a) ;a变了 |
删除元素(无副作用) | (remove "b" a) ;a不变 |
头部插入一个 | (push "hi" a) |
头部删除一个 | (pop a) |
尾部插入一个(有副作用) | (nconc a '("x")) |
尾部插入一个(无副作用) | (append a '("x")) |
删除尾部多项 | (nbutlast a 2) |
替换首项 | (setcar a "A") |
替换除首项的后面 | (setcdr a '("B" "C")) |
指定序号设置 | (setf (elt a 0) "A") |
Vector 说明 | 示例 |
---|---|
设置变量 | (setq v (vector 1 2 3)) |
按个数创建并设置初值 | (make-vector 5 0) |
创建,内部不展开 | [a b c] |
将元素统一修改 | (fillarray v 4) |
类型判断(Vector 属于 Array) | (arrayp v) |
获取 | |
---|---|
获取元素(性能好) | (aref v 2) |
获取元素(适用 Vector 和 List) | (elt v 2) |
设置 | |
---|---|
指定序号设置 | (aset v 0 "a") |
转成 List | (append v nil) |
关联列表 alist 和 Hash Table
-
alist 表示方法: (cons key value) 也可写作 (key . value), key 可以重复,有序
-
Hash Table,key 唯一,无序,量大时,随机读取性能更高;
说明 示例 取值 (alist-get 'y '((x . 1) (y . 2)))
属性列表 plist
-
plist 表示方法:
'(key1 val1 key2 val2)
, key 不能重复,长度为偶数。key 类型只能为 lisp symbol,value 可为任意类型;说明 示例 取值(eq 比较键值) (plist-get '(x 1 y 2) 'x) 取值(equal 比较键值) (lax-plist-get '("foo" 1 "bar" 2) "bar") 修改值(eq 比较),返回新 plist (plist-put '(x 1 y 2) 'x 3) 修改值(equal 比较) (let ((p '("a" 1 "b" 2))) (setq p (lax-plist-put p "b" 200))) 获取查到的键到尾部列表 (plist-member '(x 1 y 2 z 3) 'y)
网络请求
;; 同步网络请求
(with-current-buffer
(url-retrieve-synchronously "http://www.baidu.com")
(let ((data (buffer-string)))
(message "%s" data)))
;; 异步网络请求
(url-retrieve "http://www.baidu.com"
(lambda(status) (message "%s" (buffer-string))))
创建进程
(with-current-buffer (get-buffer-create "*baidu.com*")
(erase-buffer)
(make-process
:name "baidu"
:buffer (current-buffer)
:command '("curl" "-s" "www.baidu.com")
:connection-type 'pipe)
(switch-to-buffer-other-window "*baidu.com*"))
#<buffer *baidu.com*>
Lisp 的引号使用
`
和 '
类似,但 `
可以和 ,
或 @
配合展开部分内部宏
' 用来表示后面跟着符号(symbol)
参考 https://emacs-china.org/t/namespace/8402
` 其实是一个宏 backquote 的别名 (backquote.el)
(defalias '\` (symbol-function 'backquote))
比如 `(1 2 3) 其实就是 (backquote (1 2 3))
For example:
b => (ba bb bc) ; assume b has this value
`(a b c) => (a b c) ; backquote acts like quote
`(a ,b c) => (a (ba bb bc) c) ; insert the value of b
`(a ,@b c) => (a ba bb bc c) ; splice in the value of b
Vectors work just like lists. Nested backquotes are permitted.
(apply #'+ `(1 ,@(number-sequence 2 4) 5))
`(a (+ 3 4) ,(+ 3 4))
#'foo 函数声明
下列三种写法功能相同
(lambda (x) (* x x))
(function (lambda (x) (* x x)))
#'(lambda (x) (* x x))
lambda | (x) | (* x x) |
判断“相等”
说明 | 函数示例 |
---|---|
数字比较 | (= 1 1) |
字符串比较 | (equal "abc" "abc") |
数组比较(比较内部元素) | (equal [1 2 3] [1 2 3]) |
列表比较(比较内部元素) | (equal '(a b c) '(a b c)) |
对象比较(比较地址) | (eq 'a 'a) |
编写一个major mode
(define-derived-mode new-plugin-mode text-mode "new-plugin"
(interactive)
(kill-all-local-variables) ; 删除 buffer 下所有的局部变量, 避免其他 mode 的干扰
(setq major-mode 'new-plugin-mode) ; 设置当前的 mode 为 new-plugin-mode
(setq mode-name "new-plugin") ; 设置 mode 的名称
(new-plugin-highlight-keywords) ; 根据正则表达式提供语法高亮
(use-local-map new-plugin-mode-map) ; 加载 mode 对应的快捷键
(run-hooks 'new-plugin-mode-hook)) ; 加载 mode 对应的 hook, 注意 new-plugin-mode-hook 会自动生成
(defvar new-plugin-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "M-m") #'new-plugin-function) ; 绑定 new-plugin-function 函数到快捷键 Alt-m 上
map)
"Keymap used by `new-plugin-mode'.")
(defun new-plugin-highlight-keywords ()
"Highlight keywords."
;; Add keywords for highlight.
(font-lock-add-keywords
nil
'(
("regexp-string" . 'font-lock-constant-face) ; 当 buffer 内容匹配正则, 就会自动按照 font-lock-constant-face 提供颜色高亮
))
;; Enable font lock.
(font-lock-mode 1)) ; 开启语法高亮