12.18 多会话变量

如果你给某个变量赋值,然后关闭 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 命令会向用户请求输入一个数字,将其与旧值(可能是已保存的值)相加, 随后保存计算后的新值。

该机制并非设计用于存储超大的数据结构, 但对于绝大多数常规值而言,性能表现是可靠的。

Macro: define-multisession-variable name initial-value &optional doc &rest args

该宏将 name 定义为多会话变量; 若该变量此前未被赋值,则为其设置初始值 initial-valuedoc 为文档字符串,args 中可传入多个关键字参数,包括:

:package package-symbol

该关键字用于指定多会话变量所属的包,包由 package-symbol(包符号)定义。 package-symbolname(变量名)的组合必须是唯一的。 若未指定 package-symbol,则默认使用 name 符号名称的第一个「分段」—— 即名称中第一个 ‘-’(连字符)之前的部分(不包含该连字符)。 例如,若 namefoo 且未指定 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 变量的取值。

Function: multisession-value variable

该函数返回 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)” 是无法预测的。

Function: multisession-delete object

该函数会将 object(对象)及其对应的值从持久化存储中删除。

Function: make-multisession

你也可以创建不绑定到特定变量、而是显式绑定到指定包和键的持久化值。

(setq foo (make-multisession :package "mail"
                             :key "friends"))
(setf (multisession-value foo) 'everybody)

该函数支持与 define-multisession-variable 相同的关键字, 同时新增了 :initial-value 关键字,用于指定默认值。

User Option: multisession-storage

该变量用于控制多会话变量的存储方式。其默认值为 files, 表示变量值会以「一个变量对应一个文件」的结构,存储在 multisession-directory 指定的目录下。若该变量值设为 sqlite,则变量值会存储在 SQLite 数据库中; 此模式仅在 Emacs 编译时启用了 SQLite 支持的情况下可用。

User Option: multisession-directory

多会话变量会存储在该目录下,其默认值为 user-emacs-directory 目录的 multisession/ 子目录,通常路径为 ~/.emacs.d/multisession/

Command: list-multisession-values

该命令会弹出一个缓冲区,列出所有多会话变量, 并进入一个特殊模式 multisession-edit-mode — 你可在此模式下删除这些变量,或编辑它们的值。


emacs

Emacs

org-mode

Orgmode

Donations

打赏

Copyright

© 2025 Jasper Hsu

Creative Commons

Creative Commons

Attribute

Attribute

Noncommercial

Noncommercial

Share Alike

Share Alike