Emacs: 如何学习Emacs和Elisp

学会使用Emacs帮忙文档,多多练习Elisp

minibuffer增强vertico

vertico垂直展示内容更友好。

刷新包缓存 M-x package-refreesh-contents , 安装包 M-x package-install 输入 vertico

(vertico-mode 1)

帮助系统是你最好的朋友

要成为一个称职的用户,你需要掌握帮助系统。

所有帮助命令都以 C-h 键开头。开始使用这些:

C-h f
函数的帮助信息
C-h v
变量的帮助信息
C-h o
函数、变量、或的帮助信息
C-h k
快捷键绑定的帮助信息
C-h w
有关给定命令绑定到何处的帮助
C-h m
当前模式(主要和次要模式)的帮助

当光标在函数或变量的符号(专有名称)上时, C-h fC-h vC-h o 将使用该选项作为默认选项。

因为 emacs 是自文档编辑器,里面的函数变量都能找到它的文档,后续在使用 emacs 过程中会非常有帮助。

请注意,当函数或变量的符号包含两个短划线时 -- 那么这意味着它打算在文 件/包中使用。如果您计划将它们合并到您的设置中,请小心,因为它们可能会 在没有事先通知的情况下更改。

范例:

如查看C-x C-s,使用C-h k再输入C-x C-s
如save-buffer功能,使用C-h f再输入save-buffer

C-h 作为前缀和后缀

C-h 除了被用作前缀,还可以选择使用此键作为任何尚未结束的序列的后缀。

例如,Emacs 有很多以 C-x r 开头的命令。这些操作与寄存器、书签和矩形 操作有关。为了生成一个帮助缓冲区,向我们显示该序列的所有扩展,我们附加 C-h 到它,所以 C-x r C-h

您甚至可以使用 C-h 作为 C-h 的前缀的后缀作。这是一种奇特的说法,它 将 C-h C-h 提供有关可用帮助功能的特殊视图。

如果你使用的 embark 软件包,并且不想为 C-h 后缀生成帮助缓冲区,请 将以下内容添加到您的配置中:

(setq prefix-help-command #'embark-prefix-help-command)

如何阅读手册

Emacs 是一款功能强大的软件。只有在您熟悉它之后,它的潜力才会被释放出来。 这需要承诺、耐心和毅力。

换句话说:你一步一步地学习 Emacs。该过程的一部分涉及阅读通过内置信息阅 读器提供的大量文档。通过 C-h i 访问它,然后使用 C-h m 来了解有关 该模式的所有信息。

  • C-h i 内置很多文档。使用 C-h m 查看可操作的快捷键
  • C-h m 提供关于这个主模式下自信

    比如 m 指定菜单名、 n 下一节点、 p 上一节点、 ^ 向上移动一个节点、 d 到 Info 节点

范例:查看Elisp文档

  • C-h i 内置文档。
  • m Elisp : 搜索 Elisp 节点, 回车进入文档
  • m list : 搜索 Elisp 文档中 list 章节
  • m cons cells : 搜索 list 章节中 cons cells 小节
  • 对新手更好的文档是Emacs 手册,它是一个你经常访问的特殊文件,所以它有自己的键绑定:

C-h r (将“r”视为“read”的助记符)。

与所有技术文档一样,您不会一次性阅读它们。它们不是故事。相反,你一次研 究一个片段。一旦你了解了它,你就会进入下一个,逐渐拓宽你的知识(或 完善你的设置)。

用 Emacs Lisp 思考

让我们从一个非常简单的场景开始。

  • 假设您要编写一个将绑定到键的函数。
  • 这些被称为“命令”,因为它们是交互式的。
  • 此命令将在给定方向上一次将点(光标)移动 15 行。
  • 键入 C-h k 并用 C-n or C-p (移动到下一行/上一行的命令)跟踪它。你 将了解到它们分别称为 next-lineprevious-line 。帮助缓冲区告诉 你,这些命令接受一个数值参数来一次移动 N 行。它还包括指向源代码的直 接链接。通过查看源代码,您最终会推断出函数是用 defun 关键字(技术 上是 Lisp 宏)声明的。

考虑到这些,你可以切换到 *scratch* 缓冲区并开始试验:

(defun my-next-15-lines ()
  "Move to the next 15 lines."
  (interactive)                   ; this turns a function into a command
  (next-line 15))

(defun my-previous-15-lines ()
  "Move to the previous 15 lines."
  (interactive)
  (previous-line 15))

如果你仔细阅读上述帮助缓冲区,你将意识到你的代码可以改进,因为自定义代 码的正确命令是使用 forward-line 。因此,您可以相应地更新内容:

(defun my-next-15-lines ()
  "Move to the next 15 lines."
  (interactive)
  (forward-line 15))

(defun my-previous-15-lines ()
  "Move to the previous 15 lines."
  (interactive)
  (forward-line -15))

现在将它们绑定到 Ctrl+Shift,然后绑定到 n/p。要了解 Emacs 如何表示任何 键,请使用 C-h k 并键入它。你会得到 C-S-nC-S-p

(define-key global-map (kbd "C-S-n") #'my-next-15-lines)
(define-key global-map (kbd "C-S-p") #'my-previous-15-lines)

请注意,这 global-map 适用于所有主要模式。许多命令仅适用于特定模式, 因此有自己的键盘映射。 C-h k 缓冲区会相应地通知您。

试验 Elisp 条件

在前面的示例的基础上,让我们将一些变量和条件添加到组合中。下面是一个基 本变量:

(defvar my-first-toggle nil
  "If non-nil, do stuff.")

[ 通过移动到代码的末尾并键入代码 C-x C-e ,或者在 Elisp 缓冲区中键入 C-M-x 。也有 M-: 。]

让我们进入 scratch 并开始实验:

(if my-first-toggle
    (message "It is true")
  (message "It is not true"))

C-j 运行最近距离的代码

虽然这可能不切实际,但让我们添加第三个命令,它重用前两个命令:

(defun my-next-15-lines ()
  "Move to the next 15 lines."
  (interactive)
  (forward-line 15))

(defun my-previous-15-lines ()
  "Move to the previous 15 lines."
  (interactive)
  (forward-line -15))

(defun my-next-or-prev-15-lines ()
  "Move to the next or previous 15 lines.
The motion depends on the value of `my-first-toggle'."
  (interactive)
  (if my-first-toggle
      (my-next-15-lines)
    (my-previous-15-lines)))

在这种情况下,更现实的方案是让命令接受参数(即控制其行为的参数)。最简 单的是 C-u 前缀参数,您可以在命令的键之前键入该参数。

(defun my-next-or-prev-15-lines (&optional arg)
  "Move to the next or previous 15 lines.
With optional prefix ARG, move to the next lines.  Else to the previous ones."
  (interactive "P")
  ;;(if arg
  (if my-first-toggle
      (my-next-15-lines)
    (my-previous-15-lines)))

键入 C-h f 并搜索 interactive 。它会告诉你它接受的其他预设(你总是 可以编写自己的预设,但那是高级的东西)。

请注意该 &optional 类型的使用。如果没有它,如果该命令未使用 prefix 参数调用即arg,则该命令将返回错误。

练习并保持耐心

学习基础知识。永远有用的技能是使用帮助系统。

要有耐心。专业知识没有捷径可走。所有专家都是从菜鸟开始的。这也意味着你 通过反复试验的过程从错误中吸取教训:没关系。

通过尝试理解小模式来修补 Elisp。然后尝试将它们组合成更大的设计的方法。

用其他学习材料补充官方资源,例如博客文章、视频和其他人的代码。

永远——永远——阅读文档!

完整内容

;;;; C-h k  find command of =C-n=  or =C-p=

;;; 定义函数
(defun my-next-15-lines ()
  "Move to the next 15 lines."
  (interactive)                   ; this turns a function into a command
  (next-line 15)               ; instead of forward-line
  (forwad-line 15))

(defun my-previous-15-lines ()
  "Move to the previous 15 lines."
  (interactive)
  (previous-line 15))

;;; 绑定快捷键
(define-key global-map (kbd "C-S-n") #'my-next-15-lines)
(define-key global-map (kbd "C-S-p") #'my-previous-15-lines)

;;; 调用
(defvar my-first-toggle nil
  "If non-ni, do stuff.")

(if my-first-toggle
    (message "It is true")
  (message "It is no true"))

(defun my-next-or-prev-15-lines ()
  "Move to the next or previous 15 lines.
The motion depends on the value of `my-first-toggle'."
  (interactive)
  (if my-first-toggle
      (my-next-15-lines)
    (my-previous-15-lines)))

;; 可选参数arg
(defun my-next-or-prev-15-lines (&optional arg)
  "Move to the next or previous 15 lines.
With optional prefix ARG, move to the next lines.  Else to the previous ones."
  (interactive "P")
  (if my-first-toggle
  (if my-first-toggle
      (my-next-15-lines)
    (my-previous-15-lines)))

其它

中文的快速指南由水木的crazycool翻译,具体见本版1143, URL:http://www.newsmth.net/nForum/article/Emacs/34145?s=34145

  • emacs 手册: C-h rC-h m 查看帮助信息。 n p ^ 下上页,上一节