26.2 保存缓冲区

在 Emacs 中编辑文件时,你实际操作的是访问该文件的缓冲区——也就是说,文件内容会被复制到缓冲区中,你编辑的是这份副本。对缓冲区的修改不会直接写入文件,除非你保存缓冲区,即将缓冲区内容回写到文件中。对于未访问任何文件的缓冲区,在某种意义上仍可借助缓冲区局部的 write-contents-functions 钩子函数实现 “保存(saved)”。

Command: save-buffer &optional backup-option

该函数会在当前缓冲区自上次访问或保存后被修改过的情况下,将其内容保存到对应的访问文件中;否则不执行任何操作。

save-buffer 负责创建备份文件。通常情况下,backup-optionnil,且 save-buffer 仅在访问文件后的首次保存时创建备份。backup-option 取其他值时,会在不同场景下要求生成备份文件:

  • 若参数为 4 或 64(对应 1 次或 3 次 C-u),save-buffer 会标记该文件版本,在缓冲区下次保存时执行备份。
  • 若参数为 16 或 64(对应 2 次或 3 次 C-u),save-buffer 会在保存前无条件为文件的旧版本创建备份。
  • 若参数为 0,则无条件生成任何备份文件。
Command: save-some-buffers &optional save-silently-p pred

该命令用于保存部分已修改的、访问文件的缓冲区。默认情况下会逐一询问用户;但若 save-silently-pnil,则直接保存所有访问文件的缓冲区,不向用户确认。

可选参数 pred 是一个谓词函数,用于控制需要询问(或在 save-silently-p 非空时静默保存)的缓冲区。若 prednil,则使用 save-some-buffers-default-predicate 的值替代。若结果为 nil,表示仅询问访问文件的缓冲区;若为 t,则额外提供保存某些非文件缓冲区的选项——即缓冲区局部变量 buffer-offer-savenil 的缓冲区(see Killing Buffers)。用户确认保存此类非文件缓冲区时,会被要求指定保存的文件名。save-buffers-kill-emacs 函数会为 pred 传入 t

若谓词既非 t 也非 nil,则应为无参函数。该函数会在每个缓冲区中执行,以判断是否提供保存选项;若在某缓冲区中返回非空值,则表示对该缓冲区询问保存。

Command: write-file filename &optional confirm

该函数将当前缓冲区内容写入文件 filename,使缓冲区关联该文件,并标记缓冲区为未修改状态。随后会根据 filename 重命名缓冲区,必要时附加类似 ‘<2>’ 的字符串以保证缓冲区名称唯一。其核心工作通过调用 set-visited-file-name(see Buffer File Name)和 save-buffer 完成。

confirmnil,则在覆盖已有文件前要求用户确认。交互模式下默认需要确认,除非用户使用前缀参数。

filename 为目录名(see 目录名),write-file 会在该目录下使用原访问文件的文件名;若缓冲区未访问任何文件,则使用缓冲区名作为文件名。

保存缓冲区时会运行若干钩子,并执行格式转换(see 文件格式转换)。需要注意的是,下述钩子仅由 save-buffer 触发,其他将缓冲区内容写入文件的底层函数或工具不会运行这些钩子;尤其自动保存功能(see 自动保存)不会触发。

Variable: write-file-functions

该变量的值是一组函数列表,会在将缓冲区写入对应访问文件前依次调用。若其中某函数返回非空值,则视为文件已写入完成,后续函数不再执行,常规的文件写入逻辑也不再运行。

write-file-functions 中的函数返回非空值,则需自行负责创建备份文件(如适用),可执行以下代码:

(or buffer-backed-up (backup-buffer))

建议保存 backup-buffer 返回的文件权限值,并在写入文件时使用该值(非空时),这也是 save-buffer 的默认行为。See Making Backup Files

write-file-functions 中的钩子函数还需负责数据编码(如需):选择合适的编码系统与行尾转换规则(see Coding Systems in Lisp),执行编码操作(see Explicit Encoding and Decoding),并将 last-coding-system-used 设置为实际使用的编码系统(see Encoding and I/O)。

若在缓冲区中局部设置该钩子,系统会认为其与文件或缓冲区内容的获取方式相关。因此该变量被标记为永久局部变量,切换主模式不会改变其缓冲区局部值;但调用 set-visited-file-name 会重置该值。若不符合预期,可改用 write-contents-functions

尽管该变量并非常规钩子,仍可使用 add-hookremove-hook 管理列表。See 钩子

Variable: write-contents-functions

用法与 write-file-functions 类似,但适用于与缓冲区内容相关、而非与特定访问文件或路径相关的钩子,可用于为完全不关联文件的缓冲区实现自定义保存流程。此类钩子通常由主模式设置为该变量的缓冲区局部绑定。该变量一经设置即自动成为缓冲区局部变量;切换主模式会重置该变量,但调用 set-visited-file-name 不会。

若该钩子列表中任意函数返回非空值,则视为文件已写入,后续函数以及 write-file-functions 中的函数均不再执行。

使用该钩子保存无关联文件的缓冲区(如特殊模式缓冲区)时需注意:若函数保存失败并返回 nilsave-buffer 会继续提示用户指定保存文件的路径。若不希望出现此行为,可让函数通过抛出错误终止执行。

User Option: before-save-hook

该常规钩子会在缓冲区保存到对应访问文件前运行,无论保存是通过常规方式还是上述钩子完成。例如,copyright.el 程序借助该钩子确保保存文件的版权声明中使用当前年份。

User Option: after-save-hook

该常规钩子会在缓冲区成功保存到对应访问文件后运行。

User Option: file-precious-flag

若该变量非 nilsave-buffer 会在保存时防范 I/O 错误:先将新文件写入临时文件名,确认无错误后再重命名为目标文件名。该机制可避免因磁盘空间不足等问题导致文件损坏。

副作用是备份文件必须通过复制生成。See 备份方式:重命名还是复制?。同时,保存重要文件时会断开该文件与其他文件名的所有硬链接。

部分模式会在特定缓冲区中将该变量设为非空的缓冲区局部值。

User Option: require-final-newline

该变量控制文件写入时是否允许末尾换行符。若值为 tsave-buffer 会在缓冲区末尾无换行时静默添加;若为 visit,Emacs 仅在访问文件时补充缺失的换行;若为 visit-save,则访问与保存时均会补充;其他非空值下,save-buffer 会在每次遇到此类情况时询问用户是否添加换行。

若变量值为 nilsave-buffer 完全不自动添加换行。nil 为默认值,但部分主模式会在特定缓冲区中将其设为 t

另请参见函数 set-visited-file-name(see Buffer File Name)。


emacs

Emacs

org-mode

Orgmode

Donations

打赏

Copyright

© Jasper Hsu

Creative Commons

Creative Commons

Attribute

Attribute

Noncommercial

Noncommercial

Share Alike

Share Alike