Skip to content

Instantly share code, notes, and snippets.

@Bad-ptr
Last active December 12, 2015 18:18
Show Gist options
  • Save Bad-ptr/aa6be231fdc22705ca19 to your computer and use it in GitHub Desktop.
Save Bad-ptr/aa6be231fdc22705ca19 to your computer and use it in GitHub Desktop.
Manage sets of perspectives, provide save/load functionality.
(require 'perspective)
(require 'tramp)
(defcustom persp-one-initial-set-for-all-frames nil
"If nil -- new frames get each own new `perspectives-set' on creation,
Otherwise -- new frames created with the same `perspectives-set'."
:type 'boolean
:group 'perspective-mode)
(defcustom persp-auto-name-initial-set t
"If t -- autogenerate name (instead of temp-name) for initial perspectives-set,
so it will be saved even if persp-save-and-load-only-named-sets is t."
:type 'boolean
:group 'perspective-mode)
(defcustom persp-save-and-load-only-named-sets t
"If nil -- save/load all perspective sets, otherwise save/load only named sets."
:type 'boolean
:group 'perspective-mode)
(defcustom persp-auto-kill-unnamed-sets t
"If t -- On frame deletion or persps-set-switch, kill the current perspectives-set
if it's name is nil and there is no other frame using this set."
:type 'boolean
:group 'perspective-mode)
(defcustom persp-last-autokilled-set-name "*last-autokilled*"
"Last autokilled perspectives-set saved with this name in perspectives-set-hash
(not actually killed until user kill another perspectives-set)."
:type 'boolean
:group 'perspective-mode)
(cl-defstruct (perspectives-set
(:conc-name persps-set-)
(:constructor make-persps-set-internal))
(name) (temp-name) (p-last) (p-curr)
(p-hash (make-hash-table :test 'equal :size 10)))
(defvar persp-after-killed-hook nil
"A hook that's run just after a perspective is destroyed.")
(defvar perspectives-set-hash (make-hash-table :test 'equal :size 5)
"A hash containing `perspectives-set' structs.
The keys are the sets' names. The values are the `perspectives-set' structs.")
(make-variable-frame-local
(defvar persps-set-curr nil
"The perspectives-set of the current frame."))
;; New funcs -----------
(defmacro with-perspectives-set (name &rest body)
"Switch to the perspectives-set given by NAME while evaluating BODY."
(declare (indent 1))
(let ((old (cl-gensym)))
`(progn
(let ((,old (when persps-set-curr (persps-set-get-name-or-gen persps-set-curr)))
(persp-auto-kill-unnamed-sets nil))
;; (unwind-protect
(progn
(persps-set-switch ,name)
,@body)
(when ,old (persps-set-switch ,old))
;;)
))))
(defun persps-set-get-name-or-gen (p-set)
(when p-set
(or (persps-set-name p-set)
(persps-set-temp-name p-set)
(let* ((n (hash-table-count perspectives-set-hash))
(gname (format "#%s" n)))
(while (gethash gname perspectives-set-hash)
(setq n (1+ n)
gname (format "#%s" n)))
(setf (persps-set-temp-name p-set) gname)
gname))))
(defun make-persps-set (&rest args)
(let ((new (apply #'make-persps-set-internal args)))
(puthash (persps-set-get-name-or-gen new) new perspectives-set-hash)
new))
(defun persps-set-shared-or-new-empty ()
(or (and persp-one-initial-set-for-all-frames
(block 'fps
(maphash #'(lambda (k v)
(unless (string= k persp-last-autokilled-set-name)
(return-from 'fps v)))
perspectives-set-hash)))
(if (and persp-auto-name-initial-set
(< (hash-table-count perspectives-set-hash) 1))
(make-persps-set :name persp-initial-frame-name)
(make-persps-set))))
(defun persps-set-get-persp-curr-or-new ()
(when persps-set-curr
(let ((p-c (persps-set-p-curr persps-set-curr)))
(if (and p-c (not (persp-killed-p p-c)))
p-c
;;(setf (persps-set-p-curr persps-set-curr)
(make-persp :name persp-initial-frame-name :buffers (list (current-buffer))
:window-configuration (current-window-configuration)
:point-marker (point-marker))
;;)
))))
(defun persps-set-save-persp-last-curr ()
(when persps-set-curr
(setf (persps-set-p-last persps-set-curr) persp-last)
(setf (persps-set-p-curr persps-set-curr) persp-curr)))
(defun persps-set-save-state ()
(when persps-set-curr
(persps-set-save-persp-last-curr)
(persp-save)))
(defun persps-set-restore-persp-last-curr ()
(when persps-set-curr
(setq persp-last (persps-set-p-last persps-set-curr))
(setq persp-curr (persps-set-p-curr persps-set-curr))))
(defun persps-set-deactivate ()
(when persps-set-curr
(if (and persp-auto-kill-unnamed-sets
persps-set-curr
(null (persps-set-name persps-set-curr)))
(persps-set-kill (persps-set-get-name-or-gen persps-set-curr) t)
(persps-set-save-state))))
(defun persps-set-activate (persps-set &optional dont-deactivate)
(when persps-set
(unless dont-deactivate
(persps-set-deactivate))
(setq persps-set-curr persps-set
perspectives-hash (persps-set-p-hash persps-set)
persp-last (persps-set-p-last persps-set))
(persp-activate (persps-set-get-persp-curr-or-new))))
(defun persps-set-prompt (&optional default require-match)
(funcall persp-interactive-completion-function
(concat "Perspectives set name"
(if default (concat " (default " default ")") "")
": ")
(let ((ps-names))
(maphash #'(lambda (ps-name ps)
(push ps-name ps-names))
perspectives-set-hash)
ps-names)
nil require-match nil nil default))
(defun persps-set-kill (name &optional auto-kill)
(interactive "i")
(unless name
(setq name (persps-set-prompt
(persps-set-get-name-or-gen persps-set-curr)
t)))
(when name
(let ((persps-set-to-kill (gethash (if auto-kill
persp-last-autokilled-set-name
name)
perspectives-set-hash))
(persp-auto-kill-unnamed-sets nil)
(p-s-curr-name (persps-set-get-name-or-gen persps-set-curr)))
(with-perspectives-set (persps-set-get-name-or-gen persps-set-to-kill)
(maphash #'(lambda (persp-name _) (persp-kill persp-name))
perspectives-hash))
(remhash (persps-set-get-name-or-gen persps-set-to-kill)
perspectives-set-hash)
(when (and auto-kill
(not (string= name persp-last-autokilled-set-name)))
(let ((persps-set-to-save))
(puthash persp-last-autokilled-set-name persps-set-to-save
perspectives-set-hash)
(setf (persps-set-name persps-set-to-save)
nil
(persps-set-temp-name persps-set-to-save)
persp-last-autokilled-set-name)))
(when (string= name p-s-curr-name)
(persps-set-activate (persps-set-shared-or-new-empty) t)))))
(defun persps-set-rename (newname)
(interactive "sNew name: ")
(if (gethash newname perspectives-set-hash)
(persp-error "Perspectives-set `%s' already exists" name)
(when persps-set-curr
(remhash (persps-set-get-name-or-gen persps-set-curr) perspectives-set-hash)
(setf (persps-set-temp-name persps-set-curr) nil
(persps-set-name persps-set-curr) newname)
(puthash newname persps-set-curr perspectives-set-hash))))
(defun persps-set-switch (name)
(interactive "i")
(unless name (setq name (persps-set-prompt)))
(let ((new-set (or (gethash name perspectives-set-hash)
(make-persps-set :name name))))
(if (eq new-set persps-set-curr)
name
(persps-set-activate new-set))))
;; --- Hooks
(add-hook 'persp-switch-hook #'persps-set-save-persp-last-curr)
(add-hook 'persp-after-killed-hook #'persps-set-save-persp-last-curr)
(add-hook 'delete-frame-functions #'(lambda (f)
(when persp-mode
(persps-set-deactivate))))
;; --- Changed funcs
(defun persp-kill (name)
"Kill the perspective given by NAME.
Killing a perspective means that all buffers associated with that
perspective and no others are killed."
(interactive "i")
(if (null name) (setq name (persp-prompt (persp-name persp-curr) t)))
(with-perspective name
(run-hooks 'persp-killed-hook)
(mapc 'persp-remove-buffer (persp-buffers persp-curr))
(setf (persp-killed persp-curr) t))
(remhash name perspectives-hash)
(persp-update-modestring)
(when (equal name (persp-name persp-last))
(setq persp-last nil))
(when (equal name (persp-name persp-curr))
;; Don't let persp-last get set to the deleted persp.
(persp-frame-local-let ((persp-last persp-last)) (persp-switch (persp-find-some))))
(run-hooks 'persp-after-killed-hook))
(defun persp-init-frame (frame)
"Initialize the perspectives system in FRAME.
By default, this uses the current frame."
(with-selected-frame frame
(modify-frame-parameters
frame
'((perspectives-hash) (persp-curr) (persp-last) (persp-recursive) (perspective-modestring)
(persps-set-curr)))
;; Don't set these variables in modify-frame-parameters
;; because that won't do anything if they've already been accessed
(persps-set-activate (persps-set-shared-or-new-empty))
(when persp-show-modestring
(if (eq persp-show-modestring 'header)
(let ((val (or (default-value 'header-line-format) '(""))))
(unless (memq 'perspective-modestring val)
(set-default 'header-line-format (append val '(perspective-modestring)))))
(setq global-mode-string (or global-mode-string '("")))
(unless (memq 'perspective-modestring global-mode-string)
(setq global-mode-string (append global-mode-string '(perspective-modestring)))))
(persp-update-modestring))))
(cl-defun persp-buffer-in-other-p-frame (buffer)
(let ((tmp (persp-buffer-in-other-p buffer)))
(when tmp
(let ((pset (car-safe tmp)))
(when pset
(mapc #'(lambda (f)
(with-selected-frame
(when (eq persps-set-curr pset)
(cl-return-from persp-buffer-in-other-p-frame
(cons f (cdr tmp))))))
(frame-list)))))))
(cl-defun persp-buffer-in-other-p (buffer)
"Returns nil if BUFFER is only in the current perspective.
Otherwise, returns (SET . NAME), the set and name of another
perspective that has the buffer.
Prefers perspectives in the current set of selected frame."
(mapc #'(lambda (pset)
(maphash #'(lambda (persp-name persp)
(when (and (not (and (equal pset persps-set-curr)
(equal (persp-name persp) (persp-name persp-curr))))
(memq buffer (persp-buffers persp)))
(cl-return-from persp-buffer-in-other-p
(cons pset (persp-name persp)))))
(persps-set-p-hash pset)))
(let (ps-list first-item)
(maphash #'(lambda (pset-name pset)
(if (eq pset persps-set-curr)
(setq first-item pset)
(push pset ps-list)))
perspectives-set-hash)
(push first-item ps-list)
ps-list))
nil)
(defun persp-switch-to-buffer (buffer-or-name)
"Like `switch-to-buffer', but switches to another perspective if necessary."
(interactive
(list
(let ((read-buffer-function nil))
(read-buffer-to-switch "Switch to buffer: "))))
(let ((buffer (window-normalize-buffer-to-switch-to buffer-or-name)))
(if (memq buffer (persp-buffers persp-curr))
(switch-to-buffer buffer)
(let ((other-persp (persp-buffer-in-other-p-frame buffer)))
(when (eq (car-safe other-persp) (selected-frame))
(persp-switch (cdr other-persp)))
(switch-to-buffer buffer)))))
(defun persp-all-names (&optional not-frame)
(persp--all-names (with-selected-frame not-frame persps-set-curr)))
(defun persp--all-names (&optional not-pset)
"Return a list of the perspective names for all perspectives-sets.
Excludes NOT-PSET, if given."
(cl-reduce 'union
(let (persp-names)
(maphash #'(lambda (pset-name pset)
(unless (eq pset not-pset)
(let (temp-name-list)
(maphash #'(lambda (persp-name _)
(push persp-name temp-name-list))
(persps-set-p-hash pset))
(push temp-name-list persp-names))))
perspectives-set-hash)
persp-names)))
(cl-defun persp-all-get (name not-frame)
(persp--all-get name (with-selected-frame not-frame persps-set-curr)))
(cl-defun persp--all-get (name not-set)
"Returns the list of buffers for a perspective named NAME from any
set other than NOT-SET.
This doesn't return the window configuration because those can't be
copied across frames."
(maphash #'(lambda (pset-name pset)
(unless (eq pset not-pset)
(let ((persp (gethash name (persps-set-p-hash pset))))
(when persp
(cl-return-from persp-all-get (persp-buffers persp))))))
perspectives-set-hash))
(defun persp-warning (&rest args)
(message "[perspective-mode] Warning: %s" (apply #'format args)))
;; ---------------- Save ---------------------
(defcustom persp-save-dir (expand-file-name "persp-confs/" user-emacs-directory)
"The directory to/from where perspectives saved/loaded by default.
Autosave files are saved and loaded to/from this directory."
:group 'perspective-mode
:type 'directory)
(defcustom persp-auto-save-fname "persp-auto-save"
"Name of the file for auto save/load perspectives on the perspective-mode
deactivation or the emacs shutdown."
:group 'perspective-mode
:type 'string)
(defcustom persp-auto-save-num-of-backups 3
"How many autosave file backups to keep."
:group 'perspective-mode
:type 'integer)
(defcustom persp-filter-save-buffers-functions
(list #'(lambda (b) (string-prefix-p " " (buffer-name b)))
#'(lambda (b) (string-prefix-p "*" (buffer-name b))))
"If one of these functions returns t - a buffer will not be saved."
:group 'perspective-mode
:type '(repeat (function :tag "Function")))
(defcustom persp-save-buffer-functions
(list #'(lambda (b)
(when (tramp-tramp-file-p (buffer-file-name b))
`(def-buffer ,(buffer-name b)
,(persp-tramp-save-buffer-file-name b)
,(buffer-local-value 'major-mode b))))
#'(lambda (b)
(block 'persp-skip-buffer
(dolist (f-f persp-filter-save-buffers-functions)
(when (funcall f-f b)
(return-from 'persp-skip-buffer 'skip)))))
#'(lambda (b)
`(def-buffer ,(buffer-name b)
,(buffer-file-name b)
,(buffer-local-value 'major-mode b))))
"Convert a buffer to a structure that could be saved to a file.
If a function return nil -- follow to the next function in the list.
If a function return 'skip -- don't save a buffer."
:group 'perspective-mode
:type '(repeat (function :tag "Function")))
(defun persp-tramp-save-buffer-file-name (b)
(let ((persp-tramp-file-name tramp-prefix-format)
(tmh (tramp-compute-multi-hops (tramp-dissect-file-name (buffer-file-name b)))))
(while tmh
(let* ((hop (car tmh))
(method (tramp-file-name-method hop))
(user (tramp-file-name-user hop))
(host (tramp-file-name-host hop))
(filename (tramp-file-name-localname hop)))
(setq persp-tramp-file-name (concat
persp-tramp-file-name
method tramp-postfix-method-format
user tramp-postfix-user-format
host (if (= (string-width filename) 0)
tramp-postfix-hop-format
(concat tramp-postfix-host-format filename)))
tmh (cdr tmh))))
persp-tramp-file-name))
(defun persp-buffer-list-to-savelist (bufferlist)
`(def-buffers
,(let (ret)
(mapc #'(lambda (b)
(block 'persp-buffer-to-savelist
(let (tmp)
(dolist (s-f persp-save-buffer-functions)
(setq tmp (funcall s-f b))
(when tmp
(when (eq tmp 'skip) (return-from 'persp-buffer-to-savelist))
(push tmp ret)
(return-from 'persp-buffer-to-savelist tmp))))))
bufferlist)
ret)))
(defun persp-window-conf-to-savelist (persp)
`(def-winconf ,(if (not (version< emacs-version "24.3"))
(let (ret)
(with-perspective (persp-name persp)
(setq ret (window-state-get (frame-root-window) t)))
ret)
nil)))
(defun persp-local-vars-to-savelist (persp)
`(def-persp-locals ,(remove-if
#'(lambda (lvar)
(and (not (stringp lvar))
(string-match-p "#<.*?>"
(prin1-to-string lvar))
(persp-warning "The local variable %S of the perspective %s couldn't be saved."
lvar (persp-name persp))
t))
(persp-local-variables persp))))
(defun persp-to-savelist (persp &optional buffer-names)
(let ((pbn (mapcar #'(lambda (b) (buffer-name b)) (persp-buffers persp))))
(when buffer-names
(setq pbn
(delete-if-not #'(lambda (bn)
(memq bn buffer-names))
pbn)))
`(def-persp ,(and persp (persp-name persp))
(def-buffer-names ,pbn)
,(persp-window-conf-to-savelist persp)
,(persp-local-vars-to-savelist persp))))
(defun persps-set-to-savelist (p-set &optional buffer-names)
`(def-persps-set ,(and p-set (persps-set-name p-set))
(def-persps ,(let (p-sl)
(with-perspectives-set (persps-set-get-name-or-gen p-set)
(mapcar #'(lambda (persp)
(push (persp-to-savelist persp buffer-names)
p-sl))
(let (persps-list)
(maphash #'(lambda (_ persp)
(push persp persps-list))
(persps-set-p-hash p-set))
persps-list)))
p-sl))))
(defun persp-everything-to-savelist ()
(let* ((buffers-savelist (persp-buffer-list-to-savelist (buffer-list)))
(buffers-namelist (mapcar #'(lambda (bl) (cadr bl))
(cadr buffers-savelist))))
`(def-persp-config
,buffers-savelist
(def-persps-sets
,(let (ps-sl)
(maphash #'(lambda (_ p-set)
(when (or (not persp-save-and-load-only-named-sets)
(persps-set-name p-set))
(push (persps-set-to-savelist p-set buffers-namelist)
ps-sl)))
perspectives-set-hash)
ps-sl)))))
(defun persp-save-all-persps-state ()
(mapc #'(lambda (f)
(with-selected-frame f
(persps-set-save-state)))
(frame-list)))
(defsubst persp-save-with-backups (fname)
(when (and (string= fname
(concat (expand-file-name persp-save-dir)
persp-auto-save-fname))
(> persp-auto-save-num-of-backups 0))
(do ((cur persp-auto-save-num-of-backups (1- cur))
(prev (1- persp-auto-save-num-of-backups) (1- prev)))
((> 1 cur) nil)
(let ((cf (concat fname (number-to-string cur)))
(pf (concat fname (if (> prev 0)
(number-to-string prev)
""))))
(when (file-exists-p pf)
(when (file-exists-p cf)
(delete-file cf))
(rename-file pf cf t))))
(when (file-exists-p fname)
(rename-file fname (concat fname (number-to-string 1)) t)))
(write-file fname nil))
(cl-defun persp-save-state-to-file (&optional (fname persp-auto-save-fname))
(interactive (list (read-file-name "Save perspectives to file: "
persp-save-dir)))
(when fname
(let* ((p-save-dir (or (file-name-directory fname)
(expand-file-name persp-save-dir)))
(p-save-file (concat p-save-dir (file-name-nondirectory fname))))
(unless (and (file-exists-p p-save-dir)
(file-directory-p p-save-dir))
(make-directory p-save-dir t))
(if (not (and (file-exists-p p-save-dir)
(file-directory-p p-save-dir)))
(persp-error "Can't save perspectives -- `persp-save-dir'(%S) \
does not exist or not a directory." p-save-dir)
(persp-save-all-persps-state)
(let ((savelist (persp-everything-to-savelist)))
(with-temp-buffer
(erase-buffer)
(goto-char (point-min))
(insert (let ((print-length nil)
(print-level nil))
(prin1-to-string savelist)))
(persp-save-with-backups p-save-file)))))))
;; ---------- Load -----------------------
(defcustom persp-load-buffer-functions
(list #'(lambda (savelist)
(when (and savelist (eq (car savelist) 'def-buffer))
(cl-destructuring-bind (name fname mode) (cdr savelist)
(let ((buf (get-buffer name)))
(if (buffer-live-p buf)
(if (or (null fname)
(string= fname (buffer-file-name buf)))
buf
(if (file-exists-p fname)
(setq buf (find-file-noselect fname))
(persp-warning "The file %s no longer exists." fname)
(setq buf nil)))
(if (and fname (file-exists-p fname))
(setq buf (find-file-noselect fname))
(when fname
(persp-warning "The file %s no longer exists." fname))
(setq buf (get-buffer-create name))))
(when (buffer-live-p buf)
(with-current-buffer buf
(typecase mode
(function (when (and (not (eq major-mode mode))
(not (eq major-mode 'not-loaded-yet)))
(funcall mode))))))
buf)))))
"Restore a buffer from a saved structure.
If a function return nil -- follow to the next function in the list.
If a function return 'skip -- don't restore a buffer."
:group 'perspective-mode
:type '(repeat (function :tag "Function")))
(defun persp-buffers-from-savelist (savelist)
(when (and savelist (eq (car savelist) 'def-buffers))
(mapc #'(lambda (saved-buf)
(block 'persp-buffer-from-savelist
(let (tmp)
(dolist (l-f persp-load-buffer-functions)
(setq tmp (funcall l-f saved-buf))
(when tmp
(when (eq tmp 'skip)
(return-from 'persp-buffer-from-savelist))
(return-from 'persp-buffer-from-savelist))))))
(cadr savelist))))
(defun persp-window-conf-from-savelist (savelist)
(when (and savelist (eq (car savelist) 'def-winconf))
(cadr savelist)))
(defun persp-local-vars-from-savelist (savelist)
(when (and savelist (eq (car savelist) 'def-persp-locals))
(cadr savelist)))
(defun persp-get-or-new (name)
(or (gethash name perspectives-hash)
(make-persp :name name)))
(defun persp-from-savelist (savelist)
(when (and savelist (eq (car savelist) 'def-persp))
(cl-destructuring-bind (name buffer-names wconf locals) (cdr savelist)
(let ((persp (persp-get-or-new name)))
(when (and buffer-names (eq (car buffer-names) 'def-buffer-names))
(setf (persp-buffers persp)
(delete-if-not #'buffer-live-p
(mapcar #'(lambda (bn) (get-buffer bn)) (cadr buffer-names)))))
(when (and wconf (eq (car wconf) 'def-winconf))
(let ((cwc (current-window-configuration)))
(window-state-put (persp-window-conf-from-savelist wconf)
(frame-root-window) 'safe)
(setf (persp-window-configuration persp)
(current-window-configuration))
(with-current-buffer (window-buffer (selected-window))
(setf (persp-point-marker persp) (point-marker))
(setq special-win-conf (current-window-configuration)
special-point-marker (point-marker)))
(set-window-configuration cwc)))
(setf (persp-local-variables persp) (persp-local-vars-from-savelist locals))))))
(defun persps-set-get-or-new (name)
(or (gethash name perspectives-set-hash)
(make-persps-set :name name)))
(defun persps-set-from-savelist (savelist)
(when (and savelist (eq (car savelist) 'def-persps-set))
(cl-destructuring-bind (name persps) (cdr savelist)
(when (or (not persp-save-and-load-only-named-sets)
name)
(let ((p-set (persps-set-get-or-new name))
(original-persp-save (symbol-function 'persp-save))
(special-point-marker (point-marker))
(special-win-conf (current-window-configuration)))
(flet ((persp-save ()
(flet ((point-marker ()
special-point-marker)
(current-window-configuration (&optional f)
special-win-conf))
(funcall original-persp-save))))
(with-perspectives-set (persps-set-get-name-or-gen p-set)
(when (and persps (eq (car persps) 'def-persps))
(mapc #'(lambda (persp)
(persp-from-savelist persp))
(cadr persps))))))))))
(defun persp-everything-from-savelist (savelist)
(when (and savelist (eq (car savelist) 'def-persp-config))
(cl-destructuring-bind (bufferlist persps-sets) (cdr savelist)
(persp-buffers-from-savelist bufferlist)
(when (and persps-sets (eq (car persps-sets) 'def-persps-sets))
(mapc #'(lambda (p-set)
(persps-set-from-savelist p-set))
(cadr persps-sets))))))
(defun* persp-load-state-from-file (&optional (fname persp-auto-save-fname))
(interactive (list (read-file-name "Load perspectives from file: "
persp-save-dir)))
(when fname
(let ((p-save-file (concat (or (file-name-directory fname)
(expand-file-name persp-save-dir))
(file-name-nondirectory fname))))
(if (not (file-exists-p p-save-file))
(persp-warning "Load Error: No such file -- %S." p-save-file)
(let ((savelist (with-temp-buffer
(goto-char (point-min))
(insert-file-contents p-save-file nil nil nil t)
(read (current-buffer)))))
(persp-everything-from-savelist savelist))))
(mapc #'(lambda (f)
(with-selected-frame f
(when persp-curr
(set-window-configuration (persp-window-configuration persp-curr)))))
(frame-list))))
;; -------- Auto Save/Load ---------------
(defcustom persp-auto-save-opt 1
"This variable controls the autosave functionality of the persp-mode:
0 -- do not auto save;
1 -- save on the emacs shutdown and only if the persp-mode active;"
:group 'perspective-mode
:type '(choice (integer :tag "Do not save" :value 0)
(integer :tag "Save on exit" :value 1)))
(defcustom persp-auto-resume-time 3.0
"Delay time in seconds before loading from the autosave file. If <= 0 -- do not autoresume."
:group 'perspective-mode
:type 'float)
(defun persp-auto-save-on-exit ()
(when (and persp-mode (> persp-auto-save-opt 0))
(persp-save-state-to-file persp-auto-save-fname)))
(defun persp-auto-resume ()
(run-at-time persp-auto-resume-time nil
#'(lambda ()
(when (> persp-auto-resume-time 0)
(persp-load-state-from-file)))))
(add-hook 'kill-emacs-hook #'persp-auto-save-on-exit)
(defun persp-auto-resume-and-remove-from-after-make-frame-functions (f)
(persp-auto-resume)
(remove-hook 'after-make-frame-functions #'persp-auto-resume-and-remove-from-after-make-frame-functions))
(add-hook 'persp-mode-hook
#'(lambda ()
(if (or noninteractive
(and (daemonp)
(null (cdr (frame-list)))
(eq (selected-frame) terminal-frame)))
(add-hook 'after-make-frame-functions #'persp-auto-resume-and-remove-from-after-make-frame-functions)
(persp-auto-resume))))
(provide 'perspectives-set)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment