使用 Emacs、Org mode、anki-editor 等插件启动 Anki
距离上一篇文章已经有一段时间了,原因之一是在过去的几个月里,我一直被 Anki 所吸引 (一个间隔重复记忆卡片程序)。
如果你还没有用过,我强烈推荐你去试试。( 为什么?可以看看迈克尔·尼尔森的文章 )
在 Anki 社区中反复出现的一个问题,是如何快速生成卡片。有三种常见的方法:
- 使用 Anki 的
导入
功能读取 csv/tsv 文件 - 使用 genanki 编写 Python 脚本生成
.apkg
文件以便导入 Anki - 使用支持 AnkiConnect 的第三方浏览器插件(例如 Yomichan )
虽然这些都是可行的方法而且通常功能强大,但对于使用者来说,它们通常不具备灵活的可定制性(更改列和字段的匹配、特殊编辑、公式/高亮/表/等支持)。此外编程经验也是许多人的另一个入门障碍。
在这篇文章中,我将尝试演示一些在 Emacs 中使用 anki-editor 创建卡片的工作流程,anki-editor 用于连接 Emacs 的 org-mode 和 AnkiConnect。
结合 anki-editor
的连接能力、Emacs 的自定义能力以及 org-mode 丰富的格式化和导出支持,可以轻松地应付一些卡片生成场景:
- 应用强大的卡片编辑功能
- 当你遇到有趣的内容时,用最少的干扰来捕捉想法
- 自定义快捷键和工作流,最小化鼠标操作
- 等等…
第一次听说 Org-mode 的 Anki 用户请注意:看看 John Kitchin - org mode 太棒了 一瞥 org 的能力。 (找一支铅笔把日期记下来,以后可能会有纪念意义:))。
如果你已经知道 Org 可以编辑大纲结构,有标签系统和丰富的导出支持,你应该能够很好地读懂本文的内容。
安装注意事项:大多数安装是在 Linux 下使用 Emacs 的配置语言(Emacs Lisp) 完成的。
我将指出我认为需要引用细节的地方,并在文章的最后提供下载。但和往常一样,各个平台实际情况不一样。如果你不确定如何配置,请在下面留言,看看 我的配置信息 或者访问友好的 r/emacs 和 r/orgmode ,然后举手提问。
使用 emacs 的 org-mode 作为 Anki 的编辑器
带有 ANKI_NOTE_TYPE
属性 的 Org 条目为一个 Anki 笔记。条目的每个子标题对应 Anki 中的每个 域名
。 标签 也能一起同步到 Anki 中. anki-editor
使用属性值 ANKI_NOTE_ID
Ankh。
https://www.wenjiangs.com/wp-content/uploads/2024/10/anki-org-01-basic.mp4
推送内容到 Anki 时, anki-editor
会把 Org 树导出为与 Anki 兼容的 HTML。但如果若没有合适的 CSS 文件,结果看起来仍然很一般。
因此,我们可以替换 CSS 为 gongzhitaao/orgcss ,这是一个用于 org 导出 HTML 的简单样式表,可以为源代码块、列表、表等内容提供合适的样式。
https://www.wenjiangs.com/wp-content/uploads/2024/10/anki-org-02-update-css.mp4
除了Basic
之外,另一种常用的笔记类型是 Cloze Deletion。
https://www.wenjiangs.com/wp-content/uploads/2024/10/anki-org-03-clozing-shortcuts.mp4
(use-package anki-editor
:after org
:bind (:map org-mode-map
("<f12>" . anki-editor-cloze-region-auto-incr)
("<f11>" . anki-editor-cloze-region-dont-incr)
("<f10>" . anki-editor-reset-cloze-number)
("<f9>" . anki-editor-push-tree))
:config
(setq anki-editor-create-decks t ;; Allow anki-editor to create a new deck if it doesn't exist
anki-editor-org-tags-as-anki-tags t)
(defun anki-editor-cloze-region-auto-incr (&optional arg)
"Cloze region without hint and increase card number."
(interactive)
(anki-editor-cloze-region my-anki-editor-cloze-number "")
(setq my-anki-editor-cloze-number (1+ my-anki-editor-cloze-number))
(forward-sexp))
(defun anki-editor-cloze-region-dont-incr (&optional arg)
"Cloze region without hint using the previous card number."
(interactive)
(anki-editor-cloze-region (1- my-anki-editor-cloze-number) "")
(forward-sexp))
(defun anki-editor-reset-cloze-number (&optional arg)
"Reset cloze number to ARG or 1"
(interactive)
(setq my-anki-editor-cloze-number (or arg 1)))
(defun anki-editor-push-tree ()
"Push all notes under a tree."
(interactive)
(anki-editor-push-notes '(4))
(anki-editor-reset-cloze-number))
;; Initialize
(anki-editor-reset-cloze-number)
)
- 默认情况下
anki-editor-cloze-{dwim,region}
总是提示要求输入卡号。我不太需要提示,通常希望卡号增加就好,因此编写了两个助手函数anki-editor-cloze-region-{auto-incr,don-incr}
来跳过这些行为。(注意:这种自定义在 Emacs 社区中无处不在,用户不必等待上游实现所需的新特性。这与 Anki 社区有很大的不同,在 Anki 社区,版本更新经常会打断现有的附加组件,让最终用户束手无策,或者由于难以理解代码库的技术而推迟新特性的发布。 - 默认情况下
anki-editor-push-notes
将推送整个文件到 Anki。当文件包含实际上不需要更改的旧条目时,速度会很慢。在我的工作流程中,我将所有未完成的笔记保存在Dispatch Shelf
子树下,并在我感觉准备好了的时候推送整个子树(使用<f9>
)。一旦推送完成,我就会 把他们重定位到 在Exportd
子树中。为此我添加了anki-editor-push-tree
函数。 - 按需设置快捷键(本例中设置为
<f9>-<f12>
)。
Org-capture: 快速创建卡
现在我们知道了 Anki 笔记在 Org-mode 中的样子,我们可以定义一个模板,并使用 org-capture
在 web 上遇到不同的材料时快速创建卡片。
https://www.wenjiangs.com/wp-content/uploads/2024/10/anki-org-04-capture-basic.mp4
;; Org-capture templates
(setq org-my-anki-file "/path/to/your/anki.org")
(add-to-list 'org-capture-templates
("a" "Anki basic"
entry
(file+headline org-my-anki-file "Dispatch Shelf")
"* %<%H:%M> %^g\n:PROPERTIES:\n:ANKI_NOTE_TYPE: Basic\n:ANKI_DECK: Mega\n:END:\n** Front\n%?\n** Back\n%x\n"))
(add-to-list 'org-capture-templates
("A" "Anki cloze"
entry
(file+headline org-my-anki-file "Dispatch Shelf")
"* %<%H:%M> %^g\n:PROPERTIES:\n:ANKI_NOTE_TYPE: Cloze\n:ANKI_DECK: Mega\n:END:\n** Text\n%x\n** Extra\n"))
;; Allow Emacs to access content from clipboard.
(setq x-select-enable-clipboard t
x-select-enable-primary t)
- 什么是 org-capture?
- 注意
org-capture-templates
中的%x
: 这意味着我们希望在捕获时填充 X 剪贴板的内容。对于 Cloze 类的笔记,这将在存放在Text
域内。而对于 Basic 类笔记,我通常喜欢将它们放在Back
中,然后在Front
域中设置一个好问题。 - 尽可能懒的关键是让 Emacs 不仅读取显式复制/粘贴的内容(通过
C-c
/C-v
, 操作CLIPBOARD
selection),而且读取 当前选择的文本 (操作PRIMPARY
selection)。如此,在用鼠标高亮文本后,我可以立即在 Emacs 中调用org-capture (C-c c)
抓捕内容。参见 Clipboard - ArchWiki 了解详细信息。 - 标题在
anki-editor
中并不重要,我随便选了个%H:%M
。 - 根据 Michael Nielson 的建议 ( 搜索
Use one big deck
,我把大部分的笔记放在了一个名为Mega
的 deck 里。这对我很有帮助。如果您有许多 deck /note 类型,那就创建多个捕获模板,或者编写一些 elisp 函数来减少输入。
启用 X 剪贴板支持使 Emacs 支持其他任何应用程序的文本输入。对我来说,这些文本主要是来自 Firefox 的网络文章,有时是 PDF.js 的书籍…或者说,当我可以在 Emacs 中最好的 PDF 阅读器 pdftools
中阅读书籍时,我真的需要 PDF.js 吗?
https://www.wenjiangs.com/wp-content/uploads/2024/10/anki-org-05-pdf-tools-clozing.mp4
Emacs 命令 fill-paragraph (M-q)
有嗯鱼对齐从 PDF 复制的不规则文本时非常方便。
org-download + Flameshot: 再添加图像
最后,使用屏幕裁剪作为笔记内容也很好。值得庆幸的是 anki-editor
也支持这一点,我们只需要找到一种方便的方式在 Emacs 中下载图像即可。
https://www.wenjiangs.com/wp-content/uploads/2024/10/anki-org-06-screenshot.mp4
有许多用于向 Emacs 添加图像或屏幕快照的包。我选择了 abo-abo/org-download 和 Flameshot 的组合。虽然 Flameshot 允许我添加初步的注释,但要让它正常工作有点困难。如果你好奇,可以在 我的配置 中搜索 flameshot
来获得详细信息。
结论
在过去的几个月里,该配置让我受益匪浅。在白天,当我在 Emacs 中编写代码或浏览 web 文章时,我可以捕获代码片段或有趣的信息,而不需要切换到 Anki 桌面进行大量的鼠标操作。晚上,我会润色笔记(修正打字错误,添加上下文/图像),一锤定音,然后结束一天的工作。
可能性还不止于此。考虑到 Org 的功能,我肯定还有更有趣的应用场景。以下是我想到的:
- Org Babel 运行指定代码块,将 代码与输出 (纯文本,图片, 表格) 发送到 Anki 中:
ob-lilypond
,ob-dot
, ob-R - 使用 键盘洪 批量快速地创建卡片
- 一个以纯文本/PDF/EPUB( nov.el ) 文本处理为基础构建的 增量阅读 系统, 并结合
org-noter
(pdf-tools
的笔记工具),org-ref
(学术论文管理),org-capture
(内容捕获),( https://www.google.com/search?qorg-agenda)
(预设/截止日期提醒,进度追踪)... - 一个专门为 Anki 社区的用户平滑学习曲线而设计的 Emacs 发行版,就像 Spacemacs 对于 Vimmers 一样,包含了上述默认值合理的功能
- 等等…
希望它对 Anki 和 Emacs 的用户会有用,我相信将来会有一些大胆的、富有想象力的设计,它们来源于两者的交集。下次再见,快乐黑客,开心地学习和生活!
本文使用的下载文件
- anki-cards.el :本文中的配置代码
- anki-basic.css :basic 卡片的 css 模板. 它只是简单地将 gongzhitaao/orgcss 中的
org.css
,htmlize.css
和normalize.css
整合在一起 - anki-org-sample.org :演示使用文件局部标记和选项的 org 文件示例
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论