super-save-0.4.0/ 0000755 0001750 0001750 00000000000 14535037335 013447 5 ustar dogsleg dogsleg super-save-0.4.0/README.md 0000644 0001750 0001750 00000011542 14535037335 014731 0 ustar dogsleg dogsleg [![License GPL 3][badge-license]][copying]
[![MELPA][melpa-badge]][melpa-package]
[![MELPA Stable][melpa-stable-badge]][melpa-stable-package]
# super-save
super-save auto-saves your buffers, when certain events happen - e.g. you switch
between buffers, an Emacs frame loses focus, etc. You can think of it as both
something that augments and replaces the standard `auto-save-mode`.
## Installation
Available on all major `package.el` community maintained repos - [MELPA
Stable][] and [MELPA][] repos.
MELPA Stable is recommended as it has the latest stable version. MELPA has a
development snapshot for users who don't mind breakage but don't want to run
from a git checkout.
You can install `super-save` using the following command:
M-x package-install [RET] super-save [RET]
or if you'd rather keep it in your dotfiles:
```el
(unless (package-installed-p 'super-save)
(package-refresh-contents)
(package-install 'super-save))
```
If the installation doesn't work try refreshing the package list:
M-x package-refresh-contents
### use-package
If you're into `use-package` you can use the following snippet:
```el
(use-package super-save
:ensure t
:config
(super-save-mode +1))
```
### Emacs Prelude
super-save started its life as the extraction of a similar functionality I had
originally developed for [Emacs Prelude](https://github.com/bbatsov/prelude) and
the package is bundled with Prelude.
## Usage
Add the following to your Emacs config to enable
`super-save`:
```el
(super-save-mode +1)
```
If you want to enable the additional feature of auto-saving buffers when Emacs
is idle, add the following as well:
```el
(setq super-save-auto-save-when-idle t)
```
At this point you can probably switch off the built-in `auto-save-mode` (unless
you really care about its backups):
```el
(setq auto-save-default nil)
```
## Configuration
super-save will save files on command (e.g. `switch-to-buffer`) and hook
triggers (e.g. `focus-out-hook`).
Both of those are configurable via `super-save-triggers` and
`super-save-hook-triggers`. Here's a couple of examples:
```el
;; add integration with ace-window
(add-to-list 'super-save-triggers 'ace-window)
;; save on find-file
(add-to-list 'super-save-hook-triggers 'find-file-hook)
```
You can turn off `super-save` for remote files like this:
```el
(setq super-save-remote-files nil)
```
Sometimes you might want to exclude specific files from super-save. You can
achieve this via `super-save-exclude`, for example:
```el
(setq super-save-exclude '(".gpg"))
```
You can add predicate to `super-save-predicates`, this predicates must not take
arguments and return nil, when current buffer shouldn't save. If predicate don't
know needle of save file, then predicate must return t. Following example stop
`super-save`, when current file in Markdown mode:
```el
(add-to-list 'super-save-predicates (lambda ()
(not (eq major-mode 'markdown-mode))))
```
When saving a file automatically, Emacs will display a message in the
`*Messages*` buffer and in the echo area. If you want to suppress these
messages, you can set `super-save-silent` to `t`.
```el
;; Save silently
(setq super-save-silent t)
```
The `super-save-delete-trailing-whitespace` variable can be used to enable
deleting trailing white spaces before saving (via Emacs'
`delete-trailing-whitespace`).
```el
;; Enable deleting trailing white spaces before saving
(setq super-save-delete-trailing-whitespace t)
;; Enable deleting trailing white spaces before saving (except for the current line)
(setq super-save-delete-trailing-whitespace 'except-current-line)
```
By default, `super-save` will automatically save only the current buffer, if you
want to save all open buffers you can set `super-save-all-buffers` to `t`.
Setting this to `t` can be interesting when you make indirect buffer edits, like
when editing `grep`s results with `occur-mode` and `occur-edit-mode`, or when
running a project-wide search and replace with `project-query-replace-regexp`
and so on. In these cases, we can indirectly edit several buffers without
actually visiting or switching to these buffers. Hence, this option allow to
automatically save these buffers, even when they aren't visible in any window.
## License
Copyright © 2015-2023 Bozhidar Batsov and [contributors][].
Distributed under the GNU General Public License; type C-h C-c to view it.
[badge-license]: https://img.shields.io/badge/license-GPL_3-green.svg
[melpa-badge]: http://melpa.org/packages/super-save-badge.svg
[melpa-stable-badge]: http://stable.melpa.org/packages/super-save-badge.svg
[melpa-package]: http://melpa.org/#/super-save
[melpa-stable-package]: http://stable.melpa.org/#/super-save
[COPYING]: http://www.gnu.org/copyleft/gpl.html
[contributors]: https://github.com/bbatsov/super-save/contributors
[melpa]: http://melpa.org
[melpa stable]: http://stable.melpa.org
super-save-0.4.0/CONTRIBUTING.md 0000644 0001750 0001750 00000002701 14535037335 015700 0 ustar dogsleg dogsleg # Contributing
If you discover issues, have ideas for improvements or new features, or
want to contribute a new module, please report them to the
[issue tracker][1] of the repository or submit a pull request. Please,
try to follow these guidelines when you do so.
## Issue reporting
* Check that the issue has not already been reported.
* Check that the issue has not already been fixed in the latest code
(a.k.a. `master`).
* Be clear, concise and precise in your description of the problem.
* Open an issue with a descriptive title and a summary in grammatically correct,
complete sentences.
* Include any relevant code to the issue summary.
## Pull requests
* Read [how to properly contribute to open source projects on Github][2].
* Use a topic branch to easily amend a pull request later, if necessary.
* Write [good commit messages][3].
* Mention related tickets in the commit messages (e.g. `[Fix #N] Add missing autoload cookies`)
* Use the same coding conventions as the rest of the project.
* Verify your Emacs Lisp code with `checkdoc` (C-c ? d).
* Open a [pull request][4] that relates to *only* one subject with a clear title
and description in grammatically correct, complete sentences.
[1]: https://github.com/bbatsov/super-save/issues
[2]: http://gun.io/blog/how-to-github-fork-branch-and-pull-request
[3]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
[4]: https://help.github.com/articles/using-pull-requests
super-save-0.4.0/super-save.el 0000644 0001750 0001750 00000021410 14535037335 016061 0 ustar dogsleg dogsleg ;;; super-save.el --- Auto-save buffers, based on your activity. -*- lexical-binding: t -*-
;; Copyright © 2015-2023 Bozhidar Batsov
;; Author: Bozhidar Batsov
;; URL: https://github.com/bbatsov/super-save
;; Keywords: convenience
;; Version: 0.4.0
;; Package-Requires: ((emacs "25.1"))
;; This file is NOT part of GNU Emacs.
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;;
;; super-save saves buffers when they lose focus.
;;
;;; Code:
(require 'seq)
(defgroup super-save nil
"Smart-saving of buffers."
:group 'tools
:group 'convenience)
(defvar super-save-mode-map
(make-sparse-keymap)
"super-save mode's keymap.")
(defcustom super-save-triggers
'(switch-to-buffer other-window windmove-up windmove-down windmove-left windmove-right next-buffer previous-buffer)
"A list of commands which would trigger `super-save-command'."
:group 'super-save
:type '(repeat symbol)
:package-version '(super-save . "0.1.0"))
(defcustom super-save-hook-triggers
'(mouse-leave-buffer-hook focus-out-hook)
"A list of hooks which would trigger `super-save-command'."
:group 'super-save
:type '(repeat symbol)
:package-version '(super-save . "0.3.0"))
(defcustom super-save-auto-save-when-idle nil
"Save automatically when Emacs is idle."
:group 'super-save
:type 'boolean
:package-version '(super-save . "0.2.0"))
(defcustom super-save-all-buffers nil
"Auto-save all buffers, not just the current one.
Setting this to t can be interesting when you make indirect buffer edits, like
when editing `grep's results with `occur-mode' and 'occur-edit-mode', or when
running a project-wide search and replace with `project-query-replace-regexp'
and so on. In these cases, we can indirectly edit several buffers without
actually visiting or switching to these buffers. Hence, this option allow to
automatically save these buffers, even when they aren't visible in any window."
:group 'super-save
:type 'boolean
:package-version '(super-save . "0.4.0"))
(defcustom super-save-idle-duration 5
"Delay in seconds for which Emacs has to be idle before auto-saving.
See `super-save-auto-save-when-idle'."
:group 'super-save
:type 'integer
:package-version '(super-save . "0.2.0"))
(defcustom super-save-remote-files t
"Save remote files when t, ignore them otherwise."
:group 'super-save
:type 'boolean
:package-version '(super-save . "0.3.0"))
(defcustom super-save-silent nil
"Save silently, don't display any message."
:group 'super-save
:type 'boolean
:package-version '(super-save . "0.4.0"))
(defcustom super-save-delete-trailing-whitespace nil
"Controls whether to delete the trailing whitespace before saving.
Set to 'except-current-line if you want to avoid the current line."
:group 'super-save
:type '(choice (boolean :tag "Enable/disable deleting trailing whitespace for the whole buffer.")
(symbol :tag "Delete trailing whitespace except the current line." except-current-line))
:package-version '(super-save . "0.4.0"))
(defcustom super-save-exclude nil
"A list of regexps for `buffer-file-name' excluded from super-save.
When a `buffer-file-name' matches any of the regexps it is ignored."
:group 'super-save
:type '(repeat (choice regexp))
:package-version '(super-save . "0.4.0"))
(defcustom super-save-max-buffer-size nil
"Maximal size of buffer (in characters), for which super-save work.
Exists mostly because saving constantly huge buffers can be slow in some cases.
Set to 0 or nil to disable."
:group 'super-save
:type 'integer
:package-version '(super-save . "0.4.0"))
(defcustom super-save-predicates
'((lambda () buffer-file-name)
(lambda () (buffer-modified-p (current-buffer)))
(lambda () (file-writable-p buffer-file-name))
(lambda () (if (and super-save-max-buffer-size (> super-save-max-buffer-size 0))
(< (buffer-size) super-save-max-buffer-size)
t))
(lambda ()
(if (file-remote-p buffer-file-name) super-save-remote-files t))
(lambda () (super-save-include-p buffer-file-name)))
"Predicates, which return nil, when the buffer doesn't need to be saved.
Predicate functions don't take any arguments. If a predicate doesn't know
whether this buffer needs to be super-saved or not, then it must return t."
:group 'super-save
:type 'integer
:package-version '(super-save . "0.4.0"))
(defun super-save-include-p (filename)
"Return non-nil if FILENAME doesn't match any of the `super-save-exclude'."
(not (seq-some (lambda (regexp) (string-match-p regexp filename)) super-save-exclude)))
(defun super-save-p ()
"Return t when current buffer should be saved, otherwise return nil.
This function relies on the variable `super-save-predicates'."
(seq-every-p #'funcall super-save-predicates))
(defun super-save-delete-trailing-whitespace-maybe ()
"Delete trailing whitespace, optionally avoiding the current line.
See `super-save-delete-trailing-whitespace'."
(cond
((eq super-save-delete-trailing-whitespace 'except-current-line)
(let ((start (line-beginning-position))
(current (point)))
(save-excursion
(when (< (point-min) start)
(save-restriction
(narrow-to-region (point-min) (1- start))
(delete-trailing-whitespace)))
(when (> (point-max) current)
(save-restriction
(narrow-to-region current (point-max))
(delete-trailing-whitespace))))))
(super-save-delete-trailing-whitespace
(delete-trailing-whitespace))))
(defun super-save-buffer (buffer)
"Save BUFFER if needed, super-save style."
(with-current-buffer buffer
(save-excursion
(when (super-save-p)
(super-save-delete-trailing-whitespace-maybe)
(if super-save-silent
(with-temp-message ""
(let ((inhibit-message t)
(inhibit-redisplay t)
(message-log-max nil))
(basic-save-buffer)))
(basic-save-buffer))))))
(defun super-save-command ()
"Save the relevant buffers if needed.
When `super-save-all-buffers' is non-nil, save all modified buffers, else, save
only the current buffer."
(mapc #'super-save-buffer (if super-save-all-buffers (buffer-list) (list (current-buffer)))))
(defvar super-save-idle-timer)
(defun super-save-command-advice (&rest _args)
"A simple wrapper around `super-save-command' that's advice-friendly."
(super-save-command))
(defun super-save-advise-trigger-commands ()
"Apply super-save advice to the commands listed in `super-save-triggers'."
(mapc
(lambda (command)
(advice-add command :before #'super-save-command-advice))
super-save-triggers))
(defun super-save-remove-advice-from-trigger-commands ()
"Remove super-save advice from to the commands listed in `super-save-triggers'."
(mapc
(lambda (command)
(advice-remove command #'super-save-command-advice))
super-save-triggers))
(defun super-save-initialize-idle-timer ()
"Initialize super-save idle timer if `super-save-auto-save-when-idle' is true."
(setq super-save-idle-timer
(when super-save-auto-save-when-idle
(run-with-idle-timer super-save-idle-duration t #'super-save-command))))
(defun super-save-stop-idle-timer ()
"Stop super-save idle timer if `super-save-idle-timer' is set."
(when super-save-idle-timer (cancel-timer super-save-idle-timer)))
(defun super-save-initialize ()
"Setup super-save's advices and hooks."
(super-save-advise-trigger-commands)
(super-save-initialize-idle-timer)
(dolist (hook super-save-hook-triggers)
(add-hook hook #'super-save-command)))
(defun super-save-stop ()
"Cleanup super-save's advices and hooks."
(super-save-remove-advice-from-trigger-commands)
(super-save-stop-idle-timer)
(dolist (hook super-save-hook-triggers)
(remove-hook hook #'super-save-command)))
;;;###autoload
(define-minor-mode super-save-mode
"A minor mode that saves your Emacs buffers when they lose focus."
:lighter " super-save"
:keymap super-save-mode-map
:group 'super-save
:global t
(cond
(super-save-mode (super-save-initialize))
(t (super-save-stop))))
(provide 'super-save)
;;; super-save.el ends here
super-save-0.4.0/changelog.md 0000644 0001750 0001750 00000004203 14535037335 015717 0 ustar dogsleg dogsleg # Changelog
## master (unreleased)
## 0.4.0 (2023-12-09)
### New features
- Make super-save checks customizable via `super-save-predicates`.
- Introduce defcustom `super-save-max-buffer-size` as a way to avoid auto-saving
big files.
- Introduce defcustom `super-save-exclude` (a list of regular expression) as a
way to filter out certain buffer names from being auto-saved.
- [#43](https://github.com/bbatsov/crux/issues/43) Introduce `super-save-silent`
to avoid printing messages in the `*Messages*` buffer or in the echo area.
- [#43](https://github.com/bbatsov/crux/issues/43) Introduce
`super-save-delete-trailing-whitespace` which defaults to `nil` and accepts
`t` to run `delete-trailing-whitespace` before saving the buffer. This
variable accepts only the symbol `except-current-line` to delete trailing
white spaces from all lines except the current one. This can be useful when we
are in the middle of writing some thing and we add a space at the end, in this
case, we more likely need the space to stay there instead of deleting it.
- [#44](https://github.com/bbatsov/crux/issues/44) &
[#20](https://github.com/bbatsov/crux/issues/20) Introduce
`super-save-all-buffers` to save all modified buffers instead of only the
current one.
## 0.3.0 (2018-09-29)
### New features
- [#16](https://github.com/bbatsov/crux/issues/16): Make this of hook triggers
customizable (see `super-save-hook-triggers`).
- [#18](https://github.com/bbatsov/crux/issues/18): Make it possible to disable
super-save for remote files (see `super-save-remote-files`).
### Changes
- Make `super-save-triggers` a list of symbols (it used to be a list of strings).
- Trigger super-save on `next-buffer` and `previous-buffer`.
## 0.2.0 (2016-02-21)
### New features
- [#3](https://github.com/bbatsov/crux/issues/3): Turn super-save into a global
minor-mode (`super-save-mode`).
- Add some functionality for auto-saving buffers when Emacs is idle (disabled by
default).
## 0.1.0 (2016-02-11)
Initial release. Most of super-save was an extraction of a similar functionality I had originally developed for [Emacs Prelude](https://github.com/bbatsov/prelude).