From time to time I delete files that I shouldn't and worst is files that I've been writing myself. Therefore I have many times been saved by the backup feature of Emacs.
But my problem is that Emacs only makes a backup the very first time you save a buffer. Is there a way to make Emacs do it every time I press C-x C-s?
This is what my .emacs look like currently (only the part that deals with backups):
* snip *
;; ===== Backups =====
;; Enable backup files.
(setq make-backup-files t)
;; Save all backup file in this directory.
(setq backup-directory-alist (quote ((".*" . "~/.emacs_backups/"))))
;; Always backup by copying (safest, but slowest)
(setq backup-by-copying t)
;; Append .~1~ (and increasing numbers) to end of file when saving backup
(setq version-control t)
;; Defining how many old versions of a file to keep (starting from the
;; most recent and counting backward
(setq kept-new-versions 100)
* snip *
After reading this: EmacsWiki: Force Backups
I added these lines to my .emacs:
(defun force-backup-of-buffer ()
(setq buffer-backed-up nil))
(add-hook 'before-save-hook 'force-backup-of-buffer)
It utilizes the standard back up/version control but resets the flag that indicates wether or not the buffer has been backed up this session before a save.
First two rows define a function that resets the flag that indicates wether the buffer was backed up during this session.
Last row adds an event hook that executes the function before a save.
This does exactly what I wanted.
If you want to do it on your own, here's a start:
(defun backup-and-save ()
(interactive)
(setq filename (buffer-file-name))
(write-file (concat filename (format-time-string "_" "%Y%m%d%H%M%S")))
(write-file filename)
)
It saves a copy as originalfilename_timestamp in connection with a timestamp.
You might of course adjust it to store it in a separate backup folder or add other "tweaks".
Here is what I use. It puts backups in a subdirectory of the directory
the file is in. It also saves a backup each time the file is saved.
(setq make-backup-files t ; backup of a file the first time it is saved.
backup-by-copying t ; don't clobber symlinks
version-control t ; version numbers for backup files
delete-old-versions t ; delete excess backup files silently
delete-by-moving-to-trash t
kept-old-versions 6 ; oldest versions to keep when a new numbered
; backup is made (default: 2)
kept-new-versions 9 ; newest versions to keep when a new numbered
; backup is made (default: 2)
auto-save-default t ; auto-save every buffer that visits a file
auto-save-timeout 20 ; number of seconds idle time before auto-save
; (default: 30)
auto-save-interval 200 ; number of keystrokes between auto-saves
; (default: 300)
)
;; make backup to a designated dir, mirroring the full path
;; backup to dir hung on source dir...
(add-hook 'write-file-hooks 'setBackUp)
(defun setBackUp ()
"Called by before-save-hook to set up backup location"
(defvar backupdirname "BackUps~") ; you can chose the sub dir name here
(if (not (file-exists-p backupdirname))
(make-directory backupdirname t))
(setq backup-directory-alist `(("." . ,backupdirname)))
(setq buffer-backed-up nil) ; force backup every save
nil
)
Related
I am successfully using the code below to cause emacs to save many versions of each file. But I cannot figure out what commands you use in emacs to actually load those files into a buffer.
I am expecting some kind of a history viewer command!!! I can find nothing.
(setq backup-directory-alist '(("." . "~/auto-saves")))
(setq version-control t
kept-old-versions 2 kept-new-versions 200
delete-old-versions t backup-by-copying t)
You can just open the files in which ever directory you're saving them in (~/autosaves). But the backup-walker package is way better.
Update: I highly recommend using the no-littering package to keep your ~/.emacs.d (and $HOME) clean. Here's my backup config (assuming you have use-package and melpa set up):
(use-package no-littering)
(setq make-backup-files t
vc-make-backup-files t
version-control t
kept-new-versions 128
kept-old-versions 0
delete-old-versions t
backup-by-copying t)
(defun force-backup-of-buffer ()
(setq buffer-backed-up nil))
(add-hook 'before-save-hook #'force-backup-of-buffer)
(use-package backup-walker)
(let ((dir (no-littering-expand-var-file-name "auto-save/")))
(make-directory dir t)
(add-to-list 'auto-save-file-name-transforms `(".*" ,dir t) 'append))
If you don't want to use no-littering, set backup-directory-alist, tramp-persistency-file-name, tramp-backup-directory-alist, and tramp-auto-save-directory.
(setq emacs-persistence-directory
(expand-file-name "var" user-emacs-directory))
(let ((dir (expand-file-name "backup" emacs-persistence-directory)))
(unless (file-directory-p dir)
(make-directory dir t))
(setq backup-directory-alist `(("." . ,dir))))
(let ((backup-dir (concat emacs-persistence-directory "tramp-backup/")))
(setq tramp-persistency-file-name (concat emacs-persistence-directory
"tramp")
tramp-backup-directory-alist `(("." . ,backup-dir))
tramp-auto-save-directory (concat emacs-persistence-directory
"tramp-auto-save/"))
(dolist (d (list tramp-auto-save-directory backup-dir))
(unless (file-exists-p d)
(make-directory d t))))
Side note: auto-save is a different feature than backups. Backups save a copy the first time you save a buffer (C-x C-s). Above, I have the function force-backup-of-buffer on before-save-hook to backup on every save. Autosave saves a copy every time you make a certain number of edits. For a given file, there can be many backups, but there's only one autosave.
I am leaving jpkotta's answer as the selected one, since backup-walker seems to work for others. For my OSX box, I could not get Backup-Modes to work, and backup walker is more focused on DIFFS rather than just providing access to backup files.
Here is my hacked solution it is a kinda gross, but it works for me.
You will need to edit path names for your environment.
(see https://www.emacswiki.org/emacs/ForceBackups for the original)
I tried, Backup-Modes, and Backup-Directory https://www.emacswiki.org/emacs/BackupDirectory, but this is the first things that kinda worked.)
What this does:
- It fixes emacs so it always does an auto-save (surprisingly this is NOT the default)
- it adds the command ``M-x history'' to open the backups directory.
Crude, but it works. So sad to see Emacs die!
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; FORCE-BACKUP-OF-BUFFER
;;; (See https://www.emacswiki.org/emacs/ForceBackups)
(defun dao-setup-force-backup-of-buffer()
(setq vc-make-backup-files t) ; Do backups even for version controlled files!
(setq version-control t ; Use version numbers for backups.
kept-new-versions 10 ; Number of newest versions to keep.
kept-old-versions 0 ; Number of oldest versions to keep.
delete-old-versions t ; Don't ask to delete excess backup versions.
backup-by-copying t) ; Copy all files, don't rename them.
(add-hook 'before-save-hook 'force-backup-of-buffer)
)
(defun force-backup-of-buffer ()
;; Make a special "per session" backup at the first save of each
;; emacs session.
(when (not buffer-backed-up)
;; Override the default parameters for per-session backups.
'(let ((backup-directory-alist '(("." . "~/emacs-backups")))
(kept-new-versions 3))
(backup-buffer)))
(backup-buffer)
;; Make a "per save" backup on each save. The first save results in
;; both a per-session and a per-save backup, to keep the numbering
;; of per-save backups consistent.
(let ((buffer-backed-up nil))
(backup-buffer)))
(defun history ()
(interactive)
(dired-find-file "/User/oblinger/emacs-backups")
)
I have written an Emacs extension that runs arbitrary functions when a buffer is saved. Configuration is stored per Git repo, in a .graffitist file with the following format:
(setq graffitist-rules
'((".*" . (lambda (file-name project-dir-name) ... ))))
That is, if the saved buffer filename matches the regex ".*", the provided function is executed. The Emacs Lisp code responsible for this is as follows:
(defun graffitist--run-actions-for-file ()
"Runs the action specified in the project .graffitist file for the filename of the current buffer, if any."
(let* ((filename (buffer-file-name (current-buffer)))
(project-directory (graffitist--find-project-dir filename))
(config-filename (graffitist--config-filename project-directory))
(action (graffitist--find-action config-filename filename)))
(if action
(funcall action filename project-directory))))
(defun graffitist--find-project-dir (filename)
"Finds the project directory for the specified filename. Returns nil if there is no project directory.
The project directory is defined as the first directory upwards in the hierarchy containing .git."
(let ((directory-name (locate-dominating-file filename ".git")))
(if directory-name
(file-name-as-directory directory-name)
nil)))
(defun graffitist--config-filename (project-directory)
"Returns the filename to the .graffitist configuration file for the specified project directory."
(if project-directory
(concat project-directory ".graffitist")
nil))
(defun graffitist--find-action (config-filename filename)
"Finds the first action associated with a regex that matches filename."
(if (and config-filename (file-exists-p config-filename))
(progn
(load config-filename)
(assoc-default filename graffitist-rules #'string-match))))
(add-hook 'after-save-hook #'graffitist--run-actions-for-file)
This works, but seems a bit odd. It's loading the .graffitist file every time a buffer is saved, which is expensive. Also, there's just the one graffitist-rules global that's updated each time a buffer is saved.
Is there a more idiomatic way of doing this in Emacs Lisp? That is, loading per-buffer configuration and keeping it current should the configuration file change?
Perhaps once you load a given config file, you could cache it and then make use of notifications on file changes to watch for changes on that file. If a watched file changes, clear it from the cache so it gets reloaded next time it's needed.
I use an Emacs library called buffer-stack to page through my currently open buffers. It's great because it allows me to exclude uninteresting buffers like Messages and browse through only the buffers with content I've created. I browse through these buffers with a single keystroke, A-right.
I also use Ido-mode to browse through the names of recently opened files.
However, I'd like to be able to browse through not just the filenames, but the actual files, preferably with a single keystroke.
How can I browse through recently opened files?
You can use helm-recentf and its persistent-action for this purpose.
You can select recent file with helm-recentf as below.
And you can see file content by pressing Ctrl-z(persistent-action).
you press Ctrl-z, then show it content to another window(in this case upper window) temporary.
Please see official document, if you learn about helm
Here are two possible solutions (depending on exactly the use case you want).
(defun zin/open-recent-file ()
"Open the most recent currently closed file.
This will omit currently open files, instead it will retrieve the
next oldest file in recentf-list."
(interactive)
(let* ((count 0)
(recent recentf-list)
(r-length (length recent))
(buffers (mapcar 'buffer-file-name (buffer-list))))
;; Compare next file on the list to open buffers, if open skip it.
(while (member (nth count recent)
buffers)
(setq count (1+ count))
(if (= r-length count)
(error "All recent buffers already open")))
(find-file (nth count recent))))
(lexical-let ((recent-count 0))
(defun zin/visit-recent-file ()
"Visit files on the recentf-list in descending order.
This will work backwards through recentf-list visiting each file
in turn."
(interactive)
;; If last command was not to cycle through the files, then start
;; back at the first in the list.
(unless (eq last-command 'zin/visit-recent-file)
(setq recent-count 0))
;; If current buffer is the current entry on the list, increment.
(if (equal (buffer-file-name) (nth 0 recentf-list))
(setq recent-count (1+ recent-count)))
;; Error if all entries have been processed
(if (= recent-count (length recentf-list))
(error "At oldest recent buffer"))
;; Open appropriate file.
(find-file (nth recent-count recentf-list))))
The first will go through the list of recent files (recentf-list) and open the next unopened file. The second will use recentf-list to cycle to the next buffer in the list, until all have been visited then erroring out (since the list order will change as files are reopened).
To have it restart cycling when it reaches the end, just change the (error ...) to
(setq recent-count 0)
I have a TODO file that I load emacs up to use 90% of the time. When I load emacs though it defaults to loading the scratch buffer. I would like it to load the TODO file initially. I'm very new to Emacs and have tried searching round for ways to do this using the .emacs file but nothing has worked so far.
Here are my attempts:
1: Use find-file to get the file and switch-to-buffer to load it to the screen
(switch-to-buffer (find-file "c:/Users/Seb/Documents/Emacs/TODO_List.org"))
2: Use pop-to-buffer to load the file instead
(pop-to-buffer (find-file "c:/Users/Seb/Documents/Emacs/TODO_List.org"))
3: Save the desktop so it loads the next time
(desktop-save-mode 1)
None of these are working.
Here is my full .emacs file, as you can see it's barely used!
(custom-set-variables
;; custom-set-variables was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
; '(inhibit-startup-buffer-menu t)
'(inhibit-startup-screen t)
'(initial-buffer-choice t))
(custom-set-faces
;; custom-set-faces was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
)
;; Set the current directory to the Emacs Documents dir
(cd "C:/Users/Seb/Documents/Emacs")
;; Open TODO list on start up
(pop-to-buffer (find-file "c:/Users/Seb/Documents/Emacs/TODO_List.org"))
;; Turn off the annoying tool bar at startup - to turn back on
;; just type M-x tool-bar-mode
(tool-bar-mode -1)
;; Move the mouse when cursor is near
(mouse-avoidance-mode 'cat-and-mouse)
;; This enables saving the current desktop on shutdown.
(desktop-save-mode 1)
;; XML Pretty Print
(defun xml-pretty-print (begin end)
"Pretty format XML markup in region. You need to have nxml-mode
http://www.emacswiki.org/cgi-bin/wiki/NxmlMode installed to do
this. The function inserts linebreaks to separate tags that have
nothing but whitespace between them. It then indents the markup
by using nxml's indentation rules."
(interactive "r")
(save-excursion
(nxml-mode)
(goto-char begin)
(while (search-forward-regexp "\>[ \\t]*\<" nil t)
(backward-char) (insert "\n"))
(indent-region begin end))
(message "Ah, much better!"))
In your startup file, you have this line:
'(initial-buffer-choice t))
as part of your "custom-set-variables" command. The documentation string for "initial-buffer-choice" is:
Buffer to show after starting Emacs. If the value is nil and
inhibit-startup-screen' is nil, show the startup screen. If the
value is string, visit the specified file or directory using
find-file'. If t, open the `scratch' buffer.
So, the value that you've specified ('t') is causing the *scratch* buffer to be displayed after startup. Change this line to the following and your issue should be resolved:
'(initial-buffer-choice "c:/Users/Seb/Documents/Emacs/TODO_List.org"))
How can I make Emacs retain its undo history for my buffer after doing revert-buffer or using auto-revert-mode?
In Vim, if a file that is open in a buffer is changed on disc, Vim prompts me to reload the file. I can then simply click 'u' to undo the reload if I so wish and even go back further from then. Emacs seems to trash all the undo information the moment I revert the buffer.
Emacs allows you to set revert-buffer-function to override the behaviour. Here's a revert-buffer implementation that keeps the history.
;; emacs doesn't actually save undo history with revert-buffer
;; see http://lists.gnu.org/archive/html/bug-gnu-emacs/2011-04/msg00151.html
;; fix that.
(defun revert-buffer-keep-history (&optional IGNORE-AUTO NOCONFIRM PRESERVE-MODES)
(interactive)
;; tell Emacs the modtime is fine, so we can edit the buffer
(clear-visited-file-modtime)
;; insert the current contents of the file on disk
(widen)
(delete-region (point-min) (point-max))
(insert-file-contents (buffer-file-name))
;; mark the buffer as not modified
(not-modified)
(set-visited-file-modtime))
(setq revert-buffer-function 'revert-buffer-keep-history)
You could use the before-hook to save the previous buffer-content to the kill-ring:
(add-hook 'before-revert-hook (lambda () (kill-ring-save (point-min) (point-max))))
The upcoming Emacs-24.4 does what you want by default.
I guess the obvious approach would be a function which kills the current buffer content, and then calls insert-file to read in the current content from the file.
If the changes to the file included changes to the character encoding, there might be problems? I haven't tested that.
Here's my current attempt. It's a little hairy IMO, but it works okay.
;; Allow buffer reverts to be undone
(defun my-revert-buffer (&optional ignore-auto noconfirm preserve-modes)
"Revert buffer from file in an undo-able manner."
(interactive)
(when (buffer-file-name)
;; Based upon `delphi-save-state':
;; Ensure that any buffer modifications do not have any side
;; effects beyond the actual content changes.
(let ((buffer-read-only nil)
(inhibit-read-only t)
(before-change-functions nil)
(after-change-functions nil))
(unwind-protect
(progn
;; Prevent triggering `ask-user-about-supersession-threat'
(set-visited-file-modtime)
;; Kill buffer contents and insert from associated file.
(widen)
(kill-region (point-min) (point-max))
(insert-file-contents (buffer-file-name))
;; Mark buffer as unmodified.
(set-buffer-modified-p nil))))))
(defadvice ask-user-about-supersession-threat
(around my-supersession-revert-buffer)
"Use my-revert-buffer in place of revert-buffer."
(let ((real-revert-buffer (symbol-function 'revert-buffer)))
(fset 'revert-buffer 'my-revert-buffer)
;; Note that `ask-user-about-supersession-threat' calls
;; (signal 'file-supersession ...), so we need to handle
;; the error in order to restore revert-buffer.
(unwind-protect
ad-do-it
(fset 'revert-buffer real-revert-buffer))))
(ad-activate 'ask-user-about-supersession-threat)
Annoyingly, I've only just noticed all the relevant-looking information in the revert-buffer docs, so there's probably a much simpler way to do this.
If the value of revert-buffer-function is non-nil, it is called to
do all the work for this command. Otherwise, the hooks
before-revert-hook and after-revert-hook are run at the beginning
and the end, and if revert-buffer-insert-file-contents-function is
non-nil, it is called instead of rereading visited file contents.