[分享] 关于在 macOS 上设置了save-silently 为 t ,自动保存时仍然会显示消息的问题

一直比较喜欢使用自动保存的方案,关于自动保存,这个帖子" 总结了一下自动保存的姿势 " 有一些讨论。

目前自动保存的方案中比较流行的有以下方案:

  1. 内置的 auto-save-visited-mode,这个方案直接保存修改到正在编辑的文件,不会生成其他文件。 个人比较喜欢这个方案,但保存时都会在回显区(acho area) 中提示保存的消息。在 Emacs 28 版本,可以通过设置 (setq save-silently t) 进行解决。但是 Emacs 29 以后,由于在macOS 上关于显示方面的代码改动,产生了副作用,上面的设置就不生效了,保存时仍然会看到回显区闪一下。

对于这个问题,目前的临时解决方案是过滤掉 “Saving" 开头和 “Wrote” 开头的字符串:

(setq inhibit-message-regexps '("^Saving" "^Wrote"))
(setq set-message-functions '(inhibit-message))

这个问题我也提了 Bug,但 Eli 表示目前并不会去修复 https://lists.gnu.org/archive/html/bug-gnu-emacs/2023-03/msg01974.html

下面是个人目前使用的 auto-save-visited-mode 配置:

(use-package emacs
  :custom
  (auto-save-default nil)
  (create-lockfiles nil)
  (make-backup-files nil)
  (inhibit-message-regexps '("^Saving" "^Wrote"))
  (set-message-functions '(inhibit-message))
  (auto-save-visited-interval 1)
  (auto-save-visited-predicate
   (lambda () (and (not (buffer-live-p (get-buffer " *vundo tree*")))
                   (not (string-suffix-p "gpg" (file-name-extension (buffer-name)) t))
                   (not (eq (buffer-base-buffer (get-buffer (concat "CAPTURE-" (buffer-name))))
                            (current-buffer)))
                   (or (not (boundp 'corfu--total)) (zerop corfu--total))
                   (or (not (boundp 'yas--active-snippets)) (not yas--active-snippets)))))
  :hook (after-init . auto-save-visited-mode))
  1. 通过 auto-save 包,这是本论坛懒猫大佬的包,很好用,效果同 auto-save-visited-mode,并且默认已经加了很多实用的predicate,还支持自动删除尾行空格。这也是我之前一直在用的包,切换到 auto-save-visited-mode,其实就是为了尝试下内置包。
    在功能上 auto-save.el 和 auto-save-visited-mode 策略都是定时保存全部应该保存的 buffer。

  2. 通过 super-save 这个包自动保存,这个包的方案比较温和,只保存当前的buffer,而且只在一些指定的事件中会触发保存(比如切换buffer,切换窗口,失去焦点等)。当然这个包也可以设置成定时保存。

  3. 内置的 auto-save-mode, 默认开启,可以通过 (setq auto-save-default nil)关闭
    这个方案是将修改自动保存到当前目录下的以 # 开头和结尾的同名文件,比如 #foo.txt#。 如果编辑文件是放在云盘的时候,这个文件也会被同步到云盘,就比较烦人了。
    这个方案严格来说,不叫自动保存,应该是自动备份,因为修改完成后,还需要手动保存(C-x, C-s) 进行持久化保存。

3 个赞

其实auto-save-mode就挺不错的?已经不会丢东西了,在c-x c-c的时候,它问你是否保存的时候点一下y就好了。而且这样子还有在大量误操作的时候轻松回滚的好处

auto-save 配合 git 最好用, Emacs默认保存到其他文件的策略经常污染文件系统, 操作很不方便。

auto-save-mode 是不错的,即使 emacs 进程被意外 kill 了,重启 Emacs 后,仍然可以通过 M-x recover-this-file 恢复没保存的文件内容。确实不会造成文件丢失了。

我最近也在尝试用回默认的 auto-save-mode ,大部分情况都是很好用的。但在 Windows 系统上,如果我编辑的文件是 symlink 到 iCloud 下的文件时,如果按 C-x,C-s 保存文件,iCloud 就会弹窗提示我是否要将文件移动到本地,如果移动了,云盘上的文件就丢失了。这个问题请问下有没办法解决?

1 个赞

auto-save 确实是最省事的。使用 Git,编辑好重要的部分就commit一下。编辑期间也可以通过 vundo 进行可视化的 undo/redo。

我目前遇到的唯一不适合用 auto-save 的场景是:

在写 React 前端项目时,我是习惯开着 yarn start 来保持浏览器刷新的。如果 auto-save 开着的话,相当于一直在触发浏览器更新,有时会造成 CPU 疯狂转。这种情况下我会选择关闭自动保存。

其实可以写一个 predicate, 当遇到 React 文件的时候, 采取两个措施:

  1. 降低这种Web文件自动保存的频率
  2. 离开Emacs窗口马上保存一下

其实还是期望自动保存的, 只是不要频率那么高。

2 个赞

:+1: 有道理,降低频率的方案感觉不错,有空再试试看。

其实内置 auto-save-mode 在处理长文件的时候就是使用你说的这个策略, 默认的 auto-save-timeout 是 30 秒,但是在编辑长文件时,实际的超时时间会更长一些。参考 Emacs 文档 Auto-Save-Control

时长应该跟场景有关系, 比如 npm run server 这种, 不应该和文件大小有关系, 在本地磁盘保存上, 多大文件都是瞬间保存。

1 个赞

我也是 Macos 我是用:

(defun save-buffer-silently ()
  "Save the buffer silently."
  (interactive)
  (let ((inhibit-message t))  ; temporarily disable message display
    (save-buffer)))

来保存的,这样就不会在 echo 区域输出保存的信息。因为我用的是 emacs-29 最新的分支,有些时候会闪退,所以我就加了一个 idle timer 来自动保存,每次保存的时候有提示的确会干扰思路

抄了這段代碼,發現也沒辦法做到「自動保存不要刪除空格」。

貓大的 auto-save,設置了[ (setq auto-save-delete-trailing-whitespace nil) ],也是會自動刪除空格。

mac下升級了emacs 29 之後,沒想到問題這麼多。

你抄了哪段代码?猫哥的 auto-save.el 不需要这些配置,默认已经支持了。我的这些配置是针对Emacs内置的 auto-save-visited-mode 的。

你说的是什么情况下会自动刪除空格?可以贴下你的 auto-save 配置,看看能否重现。

(use-package emacs
  :custom
  (auto-save-default nil)
  (create-lockfiles nil)
  (make-backup-files nil)
  (inhibit-message-regexps '("^Saving" "^Wrote"))
  (set-message-functions '(inhibit-message))
  (auto-save-visited-interval 1)
  (auto-save-visited-predicate
   (lambda () (and (not (buffer-live-p (get-buffer " *vundo tree*")))
                   (not (string-suffix-p "gpg" (file-name-extension (buffer-name)) t))
                   (not (eq (buffer-base-buffer (get-buffer (concat "CAPTURE-" (buffer-name))))
                            (current-buffer)))
                   (or (not (boundp 'corfu--total)) (zerop corfu--total))
                   (or (not (boundp 'yas--active-snippets)) (not yas--active-snippets)))))
  :hook (after-init . auto-save-visited-mode))

抄的這段,與貓大的一樣也是自動刪除空格,如何設置不自動刪除,或者當前行不刪除空格。

貓大的auto-save,我是這樣設置的

;;(load! "auto-save")
;;
;; (add-to-list 'load-path (expand-file-name "~/.config/doom/auto-save"))
;; (require 'auto-save)
;; (setq auto-save-idle 15)
;; (auto-save-enable)
;; (setq auto-save-silent t)   ; quietly save
;; (setq auto-save-delete-trailing-whitespace nil)

auto-save.el 默认就是关闭自动删除尾行空格功能的。你不必设置 auto-save-delete-trailing-whitespace 为 nil,不过你设置了也不会有什么坏处。

我的那段配置只是启用了 auto-save-visited-mode 进行自动保存,没有设置删除空格。

你用的是 doom 的配置?可能是你启用了其他自动删除尾行空格的包,所以在自动的保存的时候给你清除了空格。

我是使用 ws-butler 这个包进行删除空格,它不会影响当前行,因为它会用虚空格填补被删除的空格。

是的,應該是這個問題,之前沒有啟用auto-save包,所以沒察覺自動刪除行尾空格的情況。查看配置,大概只有 save-buffer,一個命令。

Emacs 29.1 在 Macos 上设置 save-silently 为 t 后,回显区己经不闪 (是因为我把mode-line 关掉使用了 echo-bar 插件)

己经可以从 auto-save 转到使用 auto-save-visited-mode 了。

对于 capture 时自动删空格的问题从 auto-save 中抄了下面这个函数,把 capture buffer 对应的文件忽略掉。暂时可用。如果能把 “CAPTURE-”对应的文件都忽略就更好了。

    (defun auto-save-delete-trailing-whitespace-except-current-line ()
      (interactive)
      (when (not (string-prefix-p "inbox" (buffer-name (buffer-base-buffer))))
        (let ((begin (line-beginning-position))
              (end (point)))
          (save-excursion
            (when (< (point-min) begin)
              (save-restriction
                (narrow-to-region (point-min) (1- begin))
                (delete-trailing-whitespace)))
            (when (> (point-max) end)
              (save-restriction
                (narrow-to-region end (point-max))
                (delete-trailing-whitespace))))))))

哪个 commit 修复这个问题了?我用的 最新的 Emacs 30 都还是会闪。还是要用开始提到的临时方案。

我修改了。

我改用 auto-save-visited-mode 时用的是 echo-bar 没有使用 mode-line ,把 mode-line 调回来之后又闪了。。。。。。