4

I was working in emacs when had a power outage, so my computer was knocked offline. After I got the computer back up, I launched emacs and tried to restore the last session. Emacs then said: "No files can be recovered from this session now". All my files were saved, so all that needs to happen them opened from the .saves-pid-hostname~ file.

I'm not sure if this is even possible after researching the issues. I found this bug report about emacs session restores. It seemed to suggest that emacs didn't perceive the files as needing to be restored because all changes had been saved to them.

What I'm looking for is a way to have emacs open the files that are listed in the saves file. This should only apply to the normal file names and excludes the files that emacs makes in-between saves, like "#filename#".

Saves File:

/home/user/Documents/2019/document1.txt
/home/user/Documents/2019/#document1.txt#
/home/user/Documents/2019/document2.txt
/home/user/Documents/2019/#document2.txt#
/home/user/Documents/2019/document3.txt
/home/user/Documents/2019/#document3.txt#
/home/user/Documents/2019/document4.txt
/home/user/Documents/2019/#document4.txt#

How do I have emacs automatically open these files? I don't need my work in emacs to be persistence across restarts, so I think desktop save mode would be over kill for the situation.

9716278
  • 173
  • 6

2 Answers2

3

If you call M-x recover-session RET you are offered a dired buffer with save files. Pressing RET on one of those files opens it in an Emacs file buffer.

You can use the following function to open all files from that buffer.

(defun find-files-in-buffer (&optional include-auto-save separator)
  "Find files listed in current buffer.
Find auto save files only if INCLUDE-AUTO-SAVE is non-nil.
SEPARATOR is used as regexp to split file names.
It defaults to the newline character.

In interactive calls INCLUDE-AUTO-SAVE is the raw prefix-argument \\[universal-argument]."
  (interactive "P")
  (unless (stringp separator)
    (setq separator "\n"))
  (let ((file-list (split-string (buffer-string) separator t)))
    (unless include-auto-save
      (setq file-list (cl-remove-if
               (lambda (file)
             (auto-save-file-name-p (file-name-nondirectory file)))
               file-list)))
    (cl-loop for file in file-list
         when (file-readable-p file)
         do (find-file file))))
Tobias
  • 32,569
  • 1
  • 34
  • 75
1

I have been using the following code (essentially, a modified version of recover-session) for decades:

(defun restart-session ()
  "Using the auto-save-list file from a previous Emacs session,
this command will reload the files from that session and/or
recover that file if an auto-save file exists for it.
This command first displays a Dired buffer showing you the
previous sessions that you can restart.
To choose one, move point to the proper line and then type C-c C-c."
  (interactive)
  (let ((ls-lisp-support-shell-wildcards t))
    (dired (concat auto-save-list-file-prefix "*")))
  (goto-char (point-min))
  (or (looking-at "Move to the session you want to restart,")
      (let ((inhibit-read-only t))
        (insert "Move to the session you want to restart,\n"
                "then type C-c C-c to select it.\n\n"
                "You can also delete some of these files;\n"
                "type d on a line to mark that file for deletion.\n\n")))
  (use-local-map (nconc (make-sparse-keymap) (current-local-map)))
  (define-key (current-local-map) "\C-c\C-c" 'restart-session-finish))

(defun restart-session-finish ()
  "Choose one saved session to restart.
This command is used in the special Dired buffer created by
\\[restart-session]."
  (interactive)
  ;; Get the name of the session file to reload/recover from.
  (let ((file (dired-get-filename))
        files-to-recover
        files-to-reload
        (buffer (get-buffer-create " *restart-session*")))
    (dired-do-flagged-delete t)
    (unwind-protect
        (save-excursion
          ;; Read in the auto-save-list file.
          (set-buffer buffer)
          (erase-buffer)
          (insert-file-contents file)
          ;; Loop thru the text of that file
          ;; and get out the names of the files to reload/recover.
          (while (not (eobp))
            (let (thisfile autofile)
              (if (eolp)
                  ;; This is a pair of lines for a non-file-visiting buffer.
                  ;; Get the auto-save file name and manufacture
                  ;; a "visited file name" from that.
                  (progn
                    (forward-line 1)
                    (setq autofile
                          (buffer-substring-no-properties
                           (point)
                           (save-excursion
                             (end-of-line)
                             (point))))
                    (setq thisfile
                          (expand-file-name
                           (substring
                            (file-name-nondirectory autofile)
                            1 -1)
                           (file-name-directory autofile)))
                    (forward-line 1))
                ;; This pair of lines is a file-visiting
                ;; buffer. Use the visited file name.
                (progn
                  (setq thisfile
                        (buffer-substring-no-properties
                         (point) (progn (end-of-line) (point))))
                  (forward-line 1)
                  (setq autofile
                        (buffer-substring-no-properties
                         (point) (progn (end-of-line) (point))))
                  (forward-line 1)))
              ;; Ignore a file if its auto-save file does not exist now.
              (if (file-exists-p autofile)
                  (setq files-to-recover (cons thisfile files-to-recover))
                (if (file-exists-p thisfile)
                    (setq files-to-reload (cons thisfile files-to-reload))))))
          (setq files-to-recover (nreverse files-to-recover))
          (setq files-to-reload (nreverse files-to-reload))
          ;; The file contains a pair of line for each auto-saved buffer.
          ;; The first line of the pair contains the visited file name
          ;; or is empty if the buffer was not visiting a file.
          ;; The second line is the auto-save file name.
          (if files-to-recover
              (map-y-or-n-p  "Recover %s? "
                             (lambda (file)
                               (condition-case nil
                                   (save-excursion (recover-file file))
                                 (error
                                  "Failed to recover `%s'" file)))
                             files-to-recover
                             '("file" "files" "recover")))
          (if files-to-reload
              (map-y-or-n-p  "Reload %s? "
                             (lambda (file)
                               (condition-case nil
                                   (save-excursion (find-file-noselect file))
                                 (error
                                  "Failed to find `%s'" file)))
                             files-to-reload
                             '("file" "files" "reload")))
          (if (not (or files-to-recover files-to-reload))
              (message
               "No files could be found or recovered from this session."))
          (kill-buffer buffer)
          (list-buffers)))))

Note: recover-session only opens files for which the auto-save file is newer than the original file. It recovers unsaved files, essentially. This restart-session reopens all of the files in the atuo-save-list file (which is what was requested), in addition to offering to recover unsaved files.

Ed Sabol
  • 141
  • 6
  • Please describe what is different w.r.t `recover-session`. Oh, and the byte-compiler says to use `with-current-buffer` instead of `save-excursion+set-buffer`. – Stefan Feb 25 '20 at 13:09
  • `recover-session` only opens files for which the auto-save file is newer than the original file. It recovers unsaved files, essentially. This reopens all of the files in the atuo-save-list file (which is what the OP requested), in addition to offering to recover unsaved files. The warning message is harmless. The elisp code predates the existence of `with-current-buffer`. You can make that change in your copy if it pleases you. – Ed Sabol Feb 25 '20 at 18:20
  • Please don't describe things in comments (which are not always visible): do it directly in the answer. – Stefan Feb 25 '20 at 21:21