如果你给某个变量赋值,然后关闭 Emacs 再重新启动, 之前赋的值不会自动恢复。 用户通常会在启动文件里设置普通变量,或是使用 Customize(see 自定义设置) 来永久保存用户选项;不同的包也会用各自的文件存储数据 (例如 Gnus 存在 .newsrc.eld,URL 库把 Cookie 存在 ~/.emacs.d/url/cookies)。
在这两种极端做法之间——也就是既要写在启动文件里的配置, 又要单独文件存放的大量应用状态——Emacs 提供了一种 在多次会话之间自动持久化数据的机制,称为 多会话变量(multisession variable)。 (该功能并非在所有系统上都可用。) 下面用一个简单示例说明这类变量的设计用途:
(define-multisession-variable foo 0)
(defun my-adder (num)
(interactive "nAdd number: ")
(setf (multisession-value foo)
(+ (multisession-value foo) num))
(message "The new number is: %s" (multisession-value foo)))
这段代码定义了变量 foo,并将其绑定到一个特殊的多会话对象上——
该对象会以值 ‘0’ 完成初始化(若该变量在前一次会话中尚未存在)。
my-adder 命令会向用户请求输入一个数字,将其与旧值(可能是已保存的值)相加,
随后保存计算后的新值。
该机制并非设计用于存储超大的数据结构, 但对于绝大多数常规值而言,性能表现是可靠的。
该宏将 name 定义为多会话变量; 若该变量此前未被赋值,则为其设置初始值 initial-value。 doc 为文档字符串,args 中可传入多个关键字参数,包括:
:package package-symbol该关键字用于指定多会话变量所属的包,包由 package-symbol(包符号)定义。
package-symbol 与 name(变量名)的组合必须是唯一的。
若未指定 package-symbol,则默认使用 name 符号名称的第一个「分段」——
即名称中第一个 ‘-’(连字符)之前的部分(不包含该连字符)。
例如,若 name 为 foo 且未指定 package-symbol,
则 package-symbol 会默认设为 foo。
:synchronized bool ¶若 bool 为非 nil 值,多会话变量可被设置为 同步(synchronized) 状态。
这意味着:当有两个并发运行的 Emacs 实例时,若另一个 Emacs 实例修改了多会话变量 foo,
当前 Emacs 实例在访问该变量值时,会自动获取这个已修改的数据。
若 synchronized 设为 nil 或未指定该参数,则不会触发同步——
所有使用该变量的 Emacs 会话中,变量值彼此独立、互不影响。
:storage storage使用指定的 storage(存储)方式。可选值为 sqlite(仅在编译时启用 SQLite 支持的 Emacs 中可用)
或 files(文件存储)。若未指定该参数,
则默认使用下文所述 multisession-storage 变量的取值。
该函数返回 variable(变量)的当前值。 若该变量在本次 Emacs 会话中从未被访问过,或其值已被外部修改, 函数会从外部存储中重新读取最新值;否则,直接返回本次会话中的当前值。 若传入的 variable 并非多会话变量,调用该函数会触发错误。
通过 multisession-value 获取的值,彼此之间不一定满足 eq 相等,
但始终满足 equal 相等。
该函数是一个广义变量(详见see 广义变量), 因此更新这类变量的方式示例如下:
(setf (multisession-value foo-bar) 'zot)
只有具备可读打印语法(see 打印表示与读入语法)的 Emacs Lisp 值, 才能通过这种方式保存。
若该多会话变量开启了同步功能,对其赋值时可能会先更新变量值。例如:
(cl-incf (multisession-value foo-bar))
这段代码会先检查该值是否已在另一个 Emacs 实例中被修改: 若有修改则获取该最新值,随后为其加 1 并存储新值。 但需注意,此操作未加锁——因此当多个实例同时更新该值时, 最终哪个实例的修改会 “生效(wins)” 是无法预测的。
该函数会将 object(对象)及其对应的值从持久化存储中删除。
你也可以创建不绑定到特定变量、而是显式绑定到指定包和键的持久化值。
(setq foo (make-multisession :package "mail"
:key "friends"))
(setf (multisession-value foo) 'everybody)
该函数支持与 define-multisession-variable 相同的关键字,
同时新增了 :initial-value 关键字,用于指定默认值。
该变量用于控制多会话变量的存储方式。其默认值为 files,
表示变量值会以「一个变量对应一个文件」的结构,存储在 multisession-directory
指定的目录下。若该变量值设为 sqlite,则变量值会存储在 SQLite 数据库中;
此模式仅在 Emacs 编译时启用了 SQLite 支持的情况下可用。
多会话变量会存储在该目录下,其默认值为 user-emacs-directory
目录的 multisession/ 子目录,通常路径为 ~/.emacs.d/multisession/。
该命令会弹出一个缓冲区,列出所有多会话变量,
并进入一个特殊模式 multisession-edit-mode — 你可在此模式下删除这些变量,或编辑它们的值。