diff --git a/core/autoload/sessions.el b/core/autoload/sessions.el
new file mode 100644
index 000000000..af9a8dc24
--- /dev/null
+++ b/core/autoload/sessions.el
@@ -0,0 +1,121 @@
+;;; core/autoload/sessions.el -*- lexical-binding: t; -*-
+
+;;
+;;; Helpers
+
+;;;###autoload
+(defun doom-save-session (&optional file)
+ "TODO"
+ (setq file (expand-file-name (or file (doom-session-file))))
+ (cond ((require 'persp-mode nil t)
+ (unless persp-mode (persp-mode +1))
+ (setq persp-auto-save-opt 0)
+ (persp-save-state-to-file file))
+ ((and (require 'frameset nil t)
+ (require 'restart-emacs nil t))
+ (let ((frameset-filter-alist (append '((client . restart-emacs--record-tty-file))
+ frameset-filter-alist))
+ (desktop-base-file-name (file-name-nondirectory file))
+ (desktop-dirname (file-name-directory file))
+ (desktop-restore-eager t)
+ desktop-file-modtime)
+ (make-directory desktop-dirname t)
+ (desktop-save desktop-dirname t)))
+ ((error "No session backend to save session with"))))
+
+;;;###autoload
+(defun doom-load-session (&optional file)
+ "TODO"
+ (setq file (expand-file-name (or file (doom-session-file))))
+ (message "Attempting to load %s" file)
+ (cond ((require 'persp-mode nil t)
+ (unless persp-mode (persp-mode +1))
+ (persp-load-state-from-file file))
+ ((and (require 'frameset nil t)
+ (require 'restart-emacs nil t))
+ (restart-emacs--restore-frames-using-desktop file))
+ ((error "No session backend to load session with")))
+ (select-frame-set-input-focus (selected-frame)))
+
+;;;###autoload
+(defun doom-session-file ()
+ "TODO"
+ (cond ((require 'persp-mode nil t)
+ (expand-file-name persp-auto-save-fname persp-save-dir))
+ ((require 'desktop nil t)
+ (desktop-full-file-name))
+ ((error "No session backend available"))))
+
+
+;;
+;;; Command line switch
+
+;;;###autoload
+(defun doom-restore-session-handler (&rest _)
+ "TODO"
+ (doom-load-session))
+
+;;;###autoload
+(add-to-list 'command-switch-alist (cons "--restore" #'doom-restore-session-handler))
+
+
+;;
+;;; Commands
+
+;;;###autoload
+(defun doom/quickload-session ()
+ "TODO"
+ (interactive)
+ (message "Restoring session...")
+ (doom-load-session)
+ (message "Session restored. Welcome back."))
+
+;;;###autoload
+(defun doom/quicksave-session ()
+ "TODO"
+ (interactive)
+ (message "Saving session")
+ (doom-save-session)
+ (message "Saving session...DONE"))
+
+;;;###autoload
+(defun doom/load-session (file)
+ "TODO"
+ (interactive
+ (let ((session-file (doom-session-file)))
+ (list (or (read-file-name "Session to restore: "
+ (file-name-directory session-file)
+ nil t
+ (file-name-nondirectory session-file))
+ (user-error "No session selected. Aborting")))))
+ (unless file
+ (error "No session file selected"))
+ (message "Loading '%s' session" file)
+ (doom-load-session file))
+
+;;;###autoload
+(defun doom/save-session (file)
+ "TODO"
+ (interactive
+ (let ((session-file (doom-session-file)))
+ (list (or (read-file-name "Save session to: "
+ (file-name-directory session-file)
+ nil nil
+ (file-name-nondirectory session-file))
+ (user-error "No session selected. Aborting")))))
+ (unless file
+ (error "No session file selected"))
+ (message "Saving '%s' session" file)
+ (doom-save-session file))
+
+;;;###autoload
+(defalias 'doom/restart #'restart-emacs)
+
+;;;###autoload
+(defun doom/restart-and-restore (&optional debug)
+ "TODO"
+ (interactive "P")
+ (doom/quicksave-session)
+ (let (confirm-kill-emacs)
+ (restart-emacs
+ (delq nil (list (if debug "--debug-init") "--restore")))))
diff --git a/core/cli/autoloads.el b/core/cli/autoloads.el
index fd49c2da8..9b1c0d9b3 100644
--- a/core/cli/autoloads.el
+++ b/core/cli/autoloads.el
@@ -37,9 +37,8 @@ it exists."
(print! (bold (green "\nFinished!")))
(message "If you have a running Emacs Session, you will need to restart it or")
(message "reload Doom for changes to take effect:\n")
- (when (fboundp '+workspace/restart-emacs-then-restore)
- (message " M-x +workspace/restart-emacs-then-restore"))
- (message " M-x restart-emacs")
+ (message " M-x doom/restart-and-restore")
+ (message " M-x doom/restart")
(message " M-x doom/reload"))
(defun doom--do-load (&rest files)
diff --git a/core/core.el b/core/core.el
index e4e860990..1b5344a7b 100644
--- a/core/core.el
+++ b/core/core.el
@@ -253,6 +253,9 @@ and `doom-exit-window-hook'."
async-byte-compile-log-file (concat doom-etc-dir "async-bytecomp.log")
auto-save-list-file-name (concat doom-cache-dir "autosave")
backup-directory-alist (list (cons "." (concat doom-cache-dir "backup/")))
+ desktop-dirname (concat doom-etc-dir "desktop")
+ desktop-base-file-name "autosave"
+ desktop-base-lock-name "autosave-lock"
pcache-directory (concat doom-cache-dir "pcache/")
request-storage-directory (concat doom-cache-dir "request")
server-auth-dir (concat doom-cache-dir "server/")
diff --git a/modules/config/default/+emacs-bindings.el b/modules/config/default/+emacs-bindings.el
index 221e634b0..198104fa8 100644
--- a/modules/config/default/+emacs-bindings.el
+++ b/modules/config/default/+emacs-bindings.el
@@ -91,9 +91,9 @@
:desc "Quit Emacs" "q" #'kill-emacs
:desc "Save and quit Emacs" "Q" #'save-buffers-kill-terminal
(:when (featurep! :feature workspaces)
- :desc "Quit Emacs & forget session" "X" #'+workspace/kill-session-and-quit
- :desc "Restart & restore Emacs" "r" #'+workspace/restart-emacs-then-restore)
- :desc "Restart Emacs" "R" #'restart-emacs)
+ :desc "Quit Emacs & forget session" "X" #'+workspace/kill-session-and-quit)
+ :desc "Restart & restore Emacs" "r" #'doom/restart-and-restore
+ :desc "Restart Emacs" "R" #'doom/restart)
;; Snippets
"&" nil ; yasnippet creates this prefix, we use a different one
(:prefix ("s" . "snippets")
@@ -123,15 +123,15 @@
:desc "Previous hunk" "[" #'git-gutter:previous-hunk)
;; Worspace and window management bindings
(:prefix ("w". "workspaces")
- :desc "Autosave session" "a" #'+workspace/save-session
+ :desc "Autosave session" "a" #'doom/quicksave-session
:desc "Display workspaces" "d" #'+workspace/display
:desc "Rename workspace" "r" #'+workspace/rename
:desc "Create workspace" "c" #'+workspace/new
:desc "Delete workspace" "k" #'+workspace/delete
- :desc "Save session" "s" (λ! (let ((current-prefix-arg '(4))) (call-interactively #'+workspace/save-session)))
+ :desc "Save session" "s" #'doom/save-session
:desc "Save workspace" "S" #'+workspace/save
- :desc "Load session" "l" #'+workspace/load-session
- :desc "Load last autosaved session" "L" #'+workspace/load-last-session
+ :desc "Load session" "l" #'doom/load-session
+ :desc "Load last autosaved session" "L" #'doom/quickload-session
:desc "Kill other buffers" "o" #'doom/kill-other-buffers
:desc "Undo window config" "u" #'winner-undo
:desc "Redo window config" "U" #'winner-redo
diff --git a/modules/config/default/+evil-bindings.el b/modules/config/default/+evil-bindings.el
index 3b75ca111..560faeb10 100644
--- a/modules/config/default/+evil-bindings.el
+++ b/modules/config/default/+evil-bindings.el
@@ -544,14 +544,12 @@
:desc "Display tab bar" "TAB" #'+workspace/display
:desc "New workspace" "n" #'+workspace/new
:desc "Load workspace from file" "l" #'+workspace/load
- :desc "Load a past session" "L" #'+workspace/load-session
:desc "Save workspace to file" "s" #'+workspace/save
- :desc "Autosave current session" "S" #'+workspace/save-session
:desc "Switch workspace" "." #'+workspace/switch-to
:desc "Delete session" "x" #'+workspace/kill-session
:desc "Delete this workspace" "d" #'+workspace/delete
:desc "Rename workspace" "r" #'+workspace/rename
- :desc "Restore last session" "R" #'+workspace/load-last-session
+ :desc "Restore last session" "R" #'+workspace/restore-last-session
:desc "Next workspace" "]" #'+workspace/switch-right
:desc "Previous workspace" "[" #'+workspace/switch-left
:desc "Switch to 1st workspace" "1" (λ! (+workspace/switch-to 0))
@@ -757,12 +755,15 @@
:desc "List project tasks" "t" #'+default/project-tasks
:desc "Invalidate cache" "x" #'projectile-invalidate-cache)
- (:prefix ("q" . "quit/restart")
+ (:prefix ("q" . "session")
:desc "Quit Emacs" "q" #'evil-quit-all
:desc "Save and quit Emacs" "Q" #'evil-save-and-quit
- :desc "Quit Emacs & forget session" "X" #'+workspace/kill-session-and-quit
- :desc "Restart & restore Emacs" "r" #'+workspace/restart-emacs-then-restore
- :desc "Restart Emacs" "R" #'restart-emacs)
+ :desc "Quick save current session" "s" #'doom/quicksave-session
+ :desc "Restore last session" "l" #'doom/quickload-session
+ :desc "Save session to file" "S" #'doom/save-session
+ :desc "Restore session from file" "L" #'doom/load-session
+ :desc "Restart & restore Emacs" "r" #'doom/restart-and-restore
+ :desc "Restart Emacs" "R" #'doom/restart)
(:when (featurep! :tools upload)
(:prefix ("r" . "remote")
diff --git a/modules/feature/workspaces/README.org b/modules/feature/workspaces/README.org
index 29f8dec1a..877280479 100644
--- a/modules/feature/workspaces/README.org
+++ b/modules/feature/workspaces/README.org
@@ -61,9 +61,9 @@ in [[../../private/default/+evil-commands.el][private/default/+evil-commands.el]
| ~+workspace/new~ | =SPC TAB n= | Create a new, blank workspace |
| ~+workspace/display~ | =SPC TAB TAB= | Display open workspaces in the mode-line |
| ~+workspace/load~ | =SPC TAB l= | Load a saved workspace into the current session |
-| ~+workspace/load-session~ | =SPC TAB L= / =:sl[oad]= | Replace current session with a saved one |
+| ~doom/quicksave-load~ | =SPC TAB L= / =:sl[oad]= | Replace current session with a saved one |
| ~+workspace/save~ | =SPC TAB s= | Save the current workspace to a file |
-| ~+workspace/save-session~ | =SPC TAB S= / =:ss[ave]= | Save current session |
+| ~doom/quicksave-save~ | =SPC TAB S= / =:ss[ave]= | Save current session |
| ~+workspace/switch-to~ | =SPC TAB .= | Switch to an open workspace |
| ~+workspace/switch-left~ | =SPC TAB [= / =[ w= / =gT= | Switch to previous workspace |
| ~+workspace/switch-right~ | =SPC TAB [= / =] w= / =gt= | Switch to next workspace |
diff --git a/modules/feature/workspaces/autoload/evil.el b/modules/feature/workspaces/autoload/evil.el
index 16f75c4e6..a18d06f74 100644
--- a/modules/feature/workspaces/autoload/evil.el
+++ b/modules/feature/workspaces/autoload/evil.el
@@ -1,20 +1,6 @@
;;; feature/workspaces/autoload/evil.el -*- lexical-binding: t; -*-
;;;###if (featurep! :feature evil)
-;;;###autoload (autoload '+workspace:save-session "feature/workspaces/autoload/evil" nil t)
-(evil-define-command +workspace:save-session (&optional bang name)
- "Ex wrapper around `+workspace/save-session'. If BANG, then autosave
-(pointless if autosaving/loading is off). If NAME is nil, default to 'last'."
- (interactive "")
- (+workspace/save-session (if bang persp-auto-save-fname name)))
-
-;;;###autoload (autoload '+workspace:load-session "feature/workspaces/autoload/evil" nil t)
-(evil-define-command +workspace:load-session (&optional bang name)
- "Ex wrapper around `+workspace/load-session'. If BANG, then load last autosave
-(pointless if autosaving/loading is off). If NAME is nil, defaults to 'last'."
- (interactive "")
- (+workspace/load-session (if bang persp-auto-save-fname name)))
-
;;;###autoload (autoload '+workspace:save "feature/workspaces/autoload/evil" nil t)
(evil-define-command +workspace:save (&optional name)
"Ex wrapper around `+workspace/save-session'."
diff --git a/modules/feature/workspaces/autoload/workspaces.el b/modules/feature/workspaces/autoload/workspaces.el
index ebd1ffc0c..aa1f62e6f 100644
--- a/modules/feature/workspaces/autoload/workspaces.el
+++ b/modules/feature/workspaces/autoload/workspaces.el
@@ -112,14 +112,6 @@ Returns t if successful, nil otherwise."
*persp-hash* (list name))
(+workspace-exists-p name))
-;;;###autoload
-(defun +workspace-load-session (&optional name)
- "Replace current session with the entire session named NAME. If NAME is nil,
-use `persp-auto-save-fname'."
- (mapc #'+workspace-delete (+workspace-list-names))
- (persp-load-state-from-file
- (expand-file-name (or name persp-auto-save-fname) persp-save-dir)))
-
;;;###autoload
(defun +workspace-save (name)
"Saves a single workspace (NAME) from the current session. Can be loaded again
@@ -134,18 +126,6 @@ Returns t on success, nil otherwise."
(and (member name (persp-list-persp-names-in-file fname))
t)))
-;;;###autoload
-(defun +workspace-save-session (&optional name)
- "Save a whole session as NAME. If NAME is nil, use `persp-auto-save-fname'.
-Return t on success, nil otherwise."
- (let ((fname (expand-file-name (or name persp-auto-save-fname)
- persp-save-dir)))
- ;; disable auto-saving on kill-emacs if autosaving (i.e. name is nil)
- (when (or (not name)
- (string= name persp-auto-save-fname))
- (setq persp-auto-save-opt 0))
- (and (persp-save-state-to-file fname) t)))
-
;;;###autoload
(defun +workspace-new (name)
"Create a new workspace named NAME. If one already exists, return nil.
@@ -206,6 +186,9 @@ throws an error."
;;
;; Commands
+;;;###autoload
+(defalias '+workspace/restore-last-session #'doom/quickload-session)
+
;;;###autoload
(defun +workspace/load (name)
"Load a workspace and switch to it. If called with C-u, try to reload the
@@ -236,46 +219,6 @@ workspace."
(+workspace-message (format "'%s' workspace saved" name) 'success)
(+workspace-error (format "Couldn't save workspace %s" name))))
-;;;###autoload
-(defun +workspace/load-session (&optional name)
- "Load a session and switch to it. If called with C-u, try to load the last
-session."
- (interactive
- (list
- (unless current-prefix-arg
- (completing-read
- "Session to load: "
- (directory-files persp-save-dir nil "^[^_.]")
- nil t))))
- (condition-case ex
- (let ((name (or name persp-auto-save-fname)))
- (+workspace-load-session name)
- (+workspace-message (format "'%s' workspace loaded" name) 'success))
- '(error (+workspace-error (cadr ex) t))))
-
-;;;###autoload
-(defun +workspace/load-last-session ()
- "Restore last session and switch to it."
- (interactive)
- (+workspace/load-session))
-
-;;;###autoload
-(defun +workspace/save-session (&optional name)
- "Save the current session. If called with C-u, prompt you for the name to save
-the session as."
- (interactive
- (list
- (when current-prefix-arg
- (completing-read
- "Save session as: "
- (directory-files persp-save-dir nil "^[^_.]")))))
- (condition-case-unless-debug ex
- (let ((name (or name persp-auto-save-fname)))
- (if (+workspace-save-session name)
- (+workspace-message (format "Saved session as '%s'" name) 'success)
- (error "Couldn't save session as '%s'" name)))
- ('error (+workspace-error ex t))))
-
;;;###autoload
(defun +workspace/rename (new-name)
"Rename the current workspace."
@@ -437,12 +380,6 @@ the next."
(t (+workspace-error "Can't delete last workspace" t)))))))
-;;;###autoload
-(defun +workspace/restart-emacs-then-restore ()
- "Restarts Emacs, then restores the session."
- (interactive)
- (restart-emacs (list "--restore")))
-
;;
;; Tabs display in minibuffer
diff --git a/modules/feature/workspaces/config.el b/modules/feature/workspaces/config.el
index ff26bb85b..7bc243468 100644
--- a/modules/feature/workspaces/config.el
+++ b/modules/feature/workspaces/config.el
@@ -5,11 +5,6 @@
;; it because it was unstable and slow; `persp-mode' is neither (and still
;; maintained).
;;
-;; By default, sessions are autosaved, but not autoloaded. Use :ss or
-;; `+workspace/save-session' to save, and :sl or `+workspace/load-session' to
-;; load the last autosaved session. You can give sessions a custom name so they
-;; can be loaded later.
-;;
;; NOTE persp-mode requires `workgroups' for file persistence in Emacs 24.4.
(defvar +workspaces-main "main"
@@ -20,11 +15,6 @@
`counsel-projectile-switch-project'. This function must take one argument: the
new project directory.")
-;; FIXME actually use this for wconf bookmark system
-(defvar +workspaces-data-file "_workspaces"
- "The basename of the file to store single workspace perspectives. Will be
-stored in `persp-save-dir'.")
-
(defvar +workspaces-on-switch-project-behavior 'non-empty
"Controls the behavior of workspaces when switching to a new project.
@@ -35,11 +25,10 @@ t Always create a new workspace for the project
associated with it.
nil Never create a new workspace on project switch.")
-;; If emacs is passed --restore, restore the last session on startup. This is
-;; used by the `+workspace/restart-emacs-then-restore' command.
-(defun +workspaces-restore-last-session (&rest _)
- (add-hook 'emacs-startup-hook #'+workspace/load-session :append))
-(add-to-list 'command-switch-alist (cons "--restore" #'+workspaces-restore-last-session))
+;; FIXME actually use this for wconf bookmark system
+(defvar +workspaces-data-file "_workspaces"
+ "The basename of the file to store single workspace perspectives. Will be
+stored in `persp-save-dir'.")
;;
@@ -64,29 +53,29 @@ workspace. Also ensures that the *Warnings* buffer will be visible in main.
Uses `+workspaces-main' to determine the name of the main workspace."
(unless persp-mode
- (persp-mode +1))
- (unless noninteractive
- (let (persp-before-switch-functions persp-activated-functions)
- (with-selected-frame frame
- ;; The default perspective persp-mode creates (`persp-nil-name') is
- ;; special and doesn't represent a real persp object, so buffers can't
- ;; really be assigned to it, among other quirks. We create a *real*
- ;; main workspace to fill this role.
- (unless (persp-get-by-name +workspaces-main)
- (persp-add-new +workspaces-main))
- ;; Switch to it if we aren't auto-loading the last session
- (when (and (string= (safe-persp-name (get-current-persp)) persp-nil-name)
- (= persp-auto-resume-time -1))
- (persp-frame-switch +workspaces-main frame)
- ;; We want to know where we are in every new daemon frame
- (when (daemonp)
- (run-at-time 0.1 nil #'+workspace/display))
- ;; Fix #319: the warnings buffer gets swallowed by creating
- ;; `+workspaces-main', so we display it manually, if it exists.
- (when-let* ((warnings (get-buffer "*Warnings*")))
- (save-excursion
- (display-buffer-in-side-window
- warnings '((window-height . shrink-window-if-larger-than-buffer))))))))))
+ (persp-mode +1)
+ (unless noninteractive
+ (let (persp-before-switch-functions persp-activated-functions)
+ (with-selected-frame frame
+ ;; The default perspective persp-mode creates (`persp-nil-name') is
+ ;; special and doesn't represent a real persp object, so buffers can't
+ ;; really be assigned to it, among other quirks. We create a *real*
+ ;; main workspace to fill this role.
+ (unless (persp-get-by-name +workspaces-main)
+ (persp-add-new +workspaces-main))
+ ;; Switch to it if we aren't auto-loading the last session
+ (when (and (string= (safe-persp-name (get-current-persp)) persp-nil-name)
+ (= persp-auto-resume-time -1))
+ (persp-frame-switch +workspaces-main frame)
+ ;; We want to know where we are in every new daemon frame
+ (when (daemonp)
+ (run-at-time 0.1 nil #'+workspace/display))
+ ;; Fix #319: the warnings buffer gets swallowed by creating
+ ;; `+workspaces-main', so we display it manually, if it exists.
+ (when-let* ((warnings (get-buffer "*Warnings*")))
+ (save-excursion
+ (display-buffer-in-side-window
+ warnings '((window-height . shrink-window-if-larger-than-buffer)))))))))))
(add-hook 'doom-post-init-hook #'+workspaces|init t)
:config
diff --git a/modules/ui/doom-dashboard/config.el b/modules/ui/doom-dashboard/config.el
index d9cdc643b..e684795b4 100644
--- a/modules/ui/doom-dashboard/config.el
+++ b/modules/ui/doom-dashboard/config.el
@@ -44,11 +44,12 @@ Possible values:
(defvar +doom-dashboard-menu-sections
'(("Reload last session"
:icon (all-the-icons-octicon "history" :face 'font-lock-keyword-face)
- :when (and (bound-and-true-p persp-mode)
- (file-exists-p (expand-file-name persp-auto-save-fname
- persp-save-dir)))
+ :when (cond ((require 'persp-mode nil t)
+ (file-exists-p (expand-file-name persp-auto-save-fname persp-save-dir)))
+ ((require 'desktop nil t)
+ (file-exists-p (desktop-full-file-name))))
:face (:inherit (font-lock-keyword-face bold))
- :action +workspace/load-last-session)
+ :action doom/quickload-session)
("Open org-agenda"
:icon (all-the-icons-octicon "calendar" :face 'font-lock-keyword-face)
:when (fboundp 'org-agenda)
@@ -107,8 +108,9 @@ PLIST can have the following properties:
initial-buffer-choice
(when (or (daemonp)
(not (cl-loop for arg in (cdr command-line-args)
- if (and (string-match-p "^[^-]" arg)
- (file-exists-p arg))
+ if (or (equal arg "--restore")
+ (and (string-match-p "^[^-]" arg)
+ (file-exists-p arg)))
return t)))
#'+doom-dashboard-initial-buffer))