之前我一直在用 @manateelazycat 的 auto-save
。很爽,但是用了一年多之后,觉得某些情形下还是太偏激了。
比如
- yasnippet 展开的时候,此时自动保存的时候就会打断 yasnippet。
- 开着类似
npm watch
的时候,自动保存会频繁触发自动编译。有时候你敲到一半停下来,代码肯定是无法通过编译的,然后就报警。。。
最近尝试了一下 super-save
,这个主要是在失去焦点的时候保存,更可控一点。而且它也有在 idle 的时候保存的选项。用了一段时间还挺好。
问题是它保存的时候仅仅保存的是当前 buffer,不会保存所有被修改的文件。
有人(@JJPandari )在这个 issue 提到过这个问题,而且也有人提了 PR。
作者口口声声说没必要,理由是当前的 buffer 已经被保存了为啥还要保存所有呢?不过其实还是会出现这种情况的。
比如在用 ivy-occur
的时候就会出现这种情况,虽然可以通过添加 wgrep-auto-save-buffer
为 t
来直接保存所有的文件,
但是在我平常的使用中,还是会出现有不在当前 buffer 的文件被修改的情况。虽然我不知道什么条件下触发的。
所以,参照这个 PR 自己先 hack 一下。
(defun save-all-buffers ()
(save-excursion
(dolist (buf (buffer-list))
(set-buffer buf)
(when (and buffer-file-name
(buffer-modified-p (current-buffer))
(file-writable-p buffer-file-name)
(if (file-remote-p buffer-file-name) super-save-remote-files t))
(save-buffer)))))
(advice-add 'super-save-command :override 'save-all-buffers)
或者如果你想在保存的时候不提示保存了哪些文件,也可以替换成 auto-save
里的那个保存函数,里面有提供这个功能。
接下来的问题是保存的时候自动删除多余的空格。
delete-trailing-whitespace
的问题是会把当前光标所在位置的行尾空白也干掉,有时候你在缩进的时候保存一下就很烦。
这个在 auto-save
中已经有实现了,把它单独拿出来也很简单,就 before-save-hook
挂一下就好。
但是还存在一个问题,写 markdown 的时候,起到换行作用的行尾空格也会被删除,这个比较烦人,于是乎可以改一下。
;;; whitespace-killer --- 删除多余的空白字符
;;; Commentary:
;;; 删除行尾空白字符但不删除 Markdown 格式的行尾空白字符
;;;
;;; TODO Markdown 删除非行尾的单行空白字符
;;;
;;; Code:
;; https://www.emacswiki.org/emacs/DeletingWhitespace#toc13
(defun whitespace-killer-delete-end-trailing-blank-lines ()
"Deletes all blank lines at the end of the file."
(interactive)
(save-excursion
(save-restriction
(widen)
(goto-char (point-max))
(delete-blank-lines))))
;; https://www.emacswiki.org/emacs/auto-save.el
(defun whitespace-killer-delete-trailing-whitespace-except-current-line ()
"Delete trailing whitespace except current line."
(interactive)
(let ((begin (line-beginning-position))
(end (line-end-position)))
(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 (1+ end) (point-max))
(delete-trailing-whitespace))))))
(defun kill-whitespace ()
"Kill whitespace."
(interactive)
(if (derived-mode-p 'markdown-mode)
(whitespace-killer-delete-end-trailing-blank-lines)
(whitespace-killer-delete-trailing-whitespace-except-current-line)))
(provide 'whitespace-killer)
;;; whitespace-killer.el ends here
然后 (add-hook 'before-save-hook 'kill-whitespace)
即可。
这样在 Markdown 及其子模式下,都只是删除文件末尾多余的空白字符,不删除行尾空白字符。
如果和你一起工作的人都不清理空格,那么你的 commit 就会充斥着各种删除空格的 diff,这个时候可以尝试一下不那么激进的 ws-butler,spacemacs 好像也用的这个。最近正在尝试使用,很不错,只会删除自己编辑过的多余空格,而不会删除打开文件的时候就已经存在的多余空格。
这个工具还有个很有意思的地方,就是删除当前行所在的缩进空格时,会留下 “虚拟空格”,而并不像上面我们做的那样仅仅是跳过当前行。也就是说,实际上硬盘上已经删除了缩进空格,但是 Emacs 里显示的还是有缩进。为了证明这一点,你可以再打开一个别的编辑器看看空格是不是真的删除了。(我试了,确实删除了,很神奇。)
剩下的问题是,Markdown 如何删除段落中多余的空白字符,比如空行的空白字符。以及结尾超过两个的空格的空白字符
aaa[空格][空格][空格]
[空格][空格][空格]
bbb
不过这种需求目前还没有那么强烈,以上的方法结合起来之后已经完全满足自己自动保存的需求了。