Changeset - 5f5ffd177fa2
[Not reviewed]
0 2 0
Sergey Pashinin - 11 years ago 2014-08-23 09:52:13
sergey@pashinin.com
Removed wg-switch-to-first-workgroup-on-find-session-file
2 files changed with 5 insertions and 12 deletions:
0 comments (0 inline, 0 general)
src/workgroups-session.el
Show inline comments
 
;;; workgroups-session.el --- Top level structure "session"
 
;;; Commentary:
 
;; Main function are: `wg-write-session-file'
 
;;; Code:
 

	
 
(require 'workgroups-variables)
 
(require 'workgroups-workgroup)
 

	
 

	
 

	
 
;;
 
;; Variables
 
;;
 

	
 
(defcustom wg-session-file "~/.emacs_workgroups"
 
  "Default filename to be used to save workgroups."
 
  :type 'file
 
  :group 'workgroups)
 
(defvaralias 'wg-default-session-file 'wg-session-file)
 

	
 
(defvar wg-incorrectly-restored-bufs nil
 
  "FIXME: docstring this.")
 
;; TODO: check it on switching WG
 

	
 
(defvar wg-record-incorrectly-restored-bufs nil
 
  "FIXME: docstring this.")
 

	
 
(defcustom wg-emacs-exit-save-behavior 'save
 
  "Determines save behavior on Emacs exit.
 
Possible values:
 

	
 
`ask'           Ask the user whether to save if there are unsaved changes
 

	
 
`save'          Call `wg-save-session' when there are unsaved changes
 

	
 
Anything else   Exit Emacs without saving changes"
 
  :type 'symbol
 
  :group 'workgroups)
 

	
 
(defcustom wg-workgroups-mode-exit-save-behavior 'save
 
  "Determines save behavior on `workgroups-mode' exit.
 
Possible values:
 

	
 
`ask'           Ask the user whether to saveif there are unsaved changes
 

	
 
`save'          Call `wg-save-session' when there are unsaved changes
 

	
 
Anything else   Exit `workgroups-mode' without saving changes"
 
  :type 'symbol
 
  :group 'workgroups)
 

	
 

	
 

	
 
;;
 
;; Function
 
;;
 

	
 
(defun wg-session-uids-consistent-p ()
 
  "Return t if there are no duplicate bufs or buf uids in the wrong places.
 
nil otherwise."
 
  (and (not (wg-dups-p (wg-buf-list) :key 'wg-buf-uid :test 'string=))
 
       (not (wg-dups-p (wg-workgroup-list) :key 'wg-workgroup-uid :test 'string=))))
 

	
 

	
 
(defun wg-find-session-file (filename)
 
  "Load a session visiting FILENAME, creating one if none already exists."
 
  (interactive "FFind session file: ")
 
  (cond ((file-exists-p filename)
 
         (let ((session (wg-read-sexp-from-file filename)))
 
           (unless (wg-session-p session)
 
             (error "%S is not a Workgroups session file." filename))
 
           (setf (wg-session-file-name session) filename)
 
           (wg-reset-internal (wg-unpickel-session-parameters session)))
 
         (wg-awhen (and wg-switch-to-first-workgroup-on-find-session-file
 
                        (wg-workgroup-list))
 

	
 
         (if wg-control-frames
 
             (wg-restore-frames))
 

	
 
         (wg-awhen (wg-workgroup-list)
 
           (if (and wg-open-this-wg
 
                    (member wg-open-this-wg (wg-workgroup-names)))
 
               (wg-switch-to-workgroup wg-open-this-wg)
 
             (if (and wg-load-last-workgroup
 
                      (member (wg-session-parameter (wg-current-session t) 'last-workgroup)
 
                              (wg-workgroup-names)))
 
                 (wg-switch-to-workgroup
 
                  (wg-session-parameter (wg-current-session t) 'last-workgroup))
 
               (wg-switch-to-workgroup (car it)))
 
             ))
 
         (if wg-control-frames
 
             (wg-restore-frames))
 
         (wg-fontified-message (:cmd "Loaded: ") (:file filename)))
 
        (t
 
         (wg-query-and-save-if-modified)
 
         (wg-reset-internal (wg-make-session :file-name filename))
 
         (wg-fontified-message
 
           (:cmd "(New Workgroups session file)")))))
 
(defalias 'wg-open-session 'wg-find-session-file)
 

	
 
(defun wg-write-session-file (filename &optional confirm)
 
  "Write the current session into file FILENAME.
 
This makes the session visit that file, and marks it as not modified.
 

	
 
If optional second arg CONFIRM is non-nil, this function asks for
 
confirmation before overwriting an existing file.  Interactively,
 
confirmation is required unless you supply a prefix argument.
 

	
 
Think of it as `write-file' for Workgroups sessions."
 
  (interactive (list (read-file-name "Save session as: ")
 
                     (not current-prefix-arg)))
 
  (when (and confirm (file-exists-p filename))
 
    (unless (y-or-n-p (format "File `%s' exists; overwrite? " filename))
 
      (error "Cancelled")))
 
  (unless (file-writable-p filename)
 
    (error "File %s can't be written to" filename))
 
  (wg-perform-session-maintenance)
 
  (setf (wg-session-file-name (wg-current-session)) filename)
 
  (setf (wg-session-version (wg-current-session)) wg-version)
 
  (if wg-control-frames
 
      (wg-save-frames))
 
  (wg-write-sexp-to-file
 
   (wg-pickel-all-session-parameters (wg-current-session))
 
   filename)
 
  (wg-mark-everything-unmodified)
 
  (wg-fontified-message (:cmd "Wrote: ") (:file filename)))
 
(defalias 'wg-save-session-as 'wg-write-session-file)
 

	
 
(defun wg-determine-session-save-file-name ()
 
  "Return the filename in which to save the session."
 
  (or (wg-session-file-name (wg-current-session))
 
      (and wg-session-load-on-start wg-session-file)))
 

	
 
(defun wg-save-session (&optional force)
 
  "Save the current Workgroups session if it's been modified.
 
Think of it as `save-buffer' for Workgroups sessions.  Optional
 
argument FORCE non-nil, or interactively with a prefix arg, save
 
the session regardless of whether it's been modified."
 
  (interactive "P")
 
  (if (and (not (wg-modified-p)) (not force))
 
      (wg-message "(The session is unmodified)")
 
    (wg-write-session-file
 
     (or (wg-determine-session-save-file-name)
 
         (read-file-name "Save session as: ")))))
 

	
 
(defun wg-reset-internal (&optional session)
 
  "Reset Workgroups, setting `wg-current-session' to SESSION.
 
Resets all frame parameters, buffer-local vars, current
 
Workgroups session object, etc.  SESSION nil defaults to a new,
 
blank session object."
 
  (mapc 'wg-reset-frame (frame-list))
 
  (mapc 'wg-reset-buffer (wg-buffer-list-emacs))
 
  (setq wg-wconfig-kill-ring nil)
 
  (setq wg-current-session (or session (wg-make-session))))
 

	
 

	
 

	
 
(defun wg-session-all-buf-uids (&optional session)
 
  "Return a new list of all unique buf uids in SESSION.
 
SESSION nil defaults to `wg-current-session'."
 
  (cl-reduce 'wg-string-list-union
 
             (wg-session-workgroup-list (or session (wg-current-session)))
 
             :key 'wg-workgroup-all-buf-uids))
 

	
 
(defun wg-buffer-list-all-uids (&optional buffer-list)
 
  "Return a list of the uids of all buffers in BUFFER-LIST in
 
which `wg-buffer-uid' is locally bound.
 
BUFFER-LIST nil defaults to `buffer-list'."
 
  (delq nil (mapcar 'wg-buffer-uid (or buffer-list (wg-buffer-list-emacs)))))
 

	
 
(defun wg-all-buf-uids (&optional session buffer-list)
 
  "Return the union of `wg-session-all-buf-uids' and `wg-buffer-list-all-uids'."
 
  (cl-union (wg-session-all-buf-uids session)
 
            (wg-buffer-list-all-uids buffer-list)
 
            :test 'string=))
 

	
 
(defun wg-gc-bufs ()
 
  "gc bufs from `wg-buf-list' that are no longer needed."
 
  (let ((all-buf-uids (wg-all-buf-uids)))
 
    (wg-asetf (wg-buf-list)
 
              (cl-remove-if-not (lambda (uid) (member uid all-buf-uids)) it
 
                                :key 'wg-buf-uid))))
 

	
 

	
 

	
 
;; FIXME: Duplicate buf names probably shouldn't be allowed.  An unrelated error
 
;; causes two *scratch* buffers to be present, triggering the "uids don't match"
 
;; error.  Write something to remove bufs with duplicate names.
 

	
 

	
 
(defun wg-perform-session-maintenance ()
 
  "Perform various maintenance operations on the current Workgroups session."
 
  (wg-update-current-workgroup-working-wconfig)
 

	
 
  ;; Update every workgroup's base wconfig with `wg-workgroup-update-base-wconfig'
 
  (dolist (workgroup (wg-workgroup-list))
 
    (wg-awhen (wg-workgroup-selected-frame-wconfig workgroup)
 
      (setf (wg-workgroup-base-wconfig workgroup) it
 
            (wg-workgroup-selected-frame-wconfig workgroup) nil)))
 

	
 
  (wg-gc-bufs)
 
  (wg-gc-buf-uids)
 
  (wg-update-buf-list))
 

	
 

	
 
;; session consistency testing
 

	
 

	
 
(defun wg-modified-p ()
 
  "Return t when the current session or any of its workgroups are modified."
 
  (or (wg-session-modified (wg-current-session))
 
      (cl-some 'wg-workgroup-modified (wg-workgroup-list))))
 

	
 
(defun wg-mark-everything-unmodified ()
 
  "Mark the session and all workgroups as unmodified."
 
  (setf (wg-session-modified (wg-current-session)) nil)
 
  (dolist (workgroup (wg-workgroup-list))
 
    (setf (wg-workgroup-modified workgroup) nil)))
 

	
 

	
 
(defun wg-workgroup-names (&optional noerror)
 
  "Return a list of workgroup names or scream unless NOERROR."
 
  (mapcar 'wg-workgroup-name (wg-workgroup-list-or-error noerror)))
 

	
 

	
 
;;; session parameters
 

	
 
(defun wg-session-parameter (session parameter &optional default)
 
  "Return SESSION's value for PARAMETER.
 
If PARAMETER is not found, return DEFAULT which defaults to nil.
 
SESSION nil defaults to the current session."
 
  (wg-aget (wg-session-parameters (or session (wg-current-session)))
 
           parameter default))
 

	
 
(defun wg-set-session-parameter (session parameter value)
 
  "Set SESSION's value of PARAMETER to VALUE.
 
SESSION nil means use the current session.
 
Return value."
 
  (let ((session (or session (wg-current-session))))
 
    (wg-set-parameter (wg-session-parameters session) parameter value)
 
    (setf (wg-session-modified session) t)
 
    value))
 

	
 
(defun wg-remove-session-parameter (session parameter)
 
  "Remove parameter PARAMETER from SESSION's parameters."
 
  (let ((session (or session (wg-current-session))))
 
    (wg-asetf (wg-session-parameters session) (wg-aremove it parameter))
 
    (setf (wg-session-modified session) t)))
 

	
 
(defun wg-session-local-value (variable &optional session)
 
  "Return the value of VARIABLE in SESSION.
 
SESSION nil defaults to the current session.  If VARIABLE does
 
not have a session-local binding in SESSION, the value is
 
resolved by Emacs."
 
  (let* ((undefined (cl-gensym))
 
         (value (wg-session-parameter session variable undefined)))
 
    (if (not (eq value undefined)) value
 
      (symbol-value variable))))
 

	
 

	
 
(defun wg-reset-frame (frame)
 
  "Reset Workgroups' frame-parameters in FRAME to nil."
 
  (set-frame-parameter frame 'wg-workgroup-state-table nil)
 
  (set-frame-parameter frame 'wg-current-workgroup-uid nil)
 
  (set-frame-parameter frame 'wg-previous-workgroup-uid nil))
 

	
 

	
 

	
 
(defun wg-save-session-on-exit (behavior)
 
  "Perform session-saving operations based on BEHAVIOR."
 
  (cl-case behavior
 
    (ask (wg-query-and-save-if-modified))
 
    (save
 
     (if (wg-determine-session-save-file-name)
 
         (wg-save-session)
 
       (wg-query-and-save-if-modified)))))
 

	
 
(defun wg-save-frames ()
 
  "Save opened frames as a session parameter.
 
Exclude `selected-frame' and daemon one (if any).
 
http://stackoverflow.com/questions/21151992/why-emacs-as-daemon-gives-1-more-frame-than-is-opened"
 
  (interactive)
 
  (let ((fl (frame-list)))
 
    (mapc (lambda (frame)
src/workgroups-variables.el
Show inline comments
 
;;; workgroups-variables --- Workgroups vars and consts
 
;;; Commentary:
 
;;; Code:
 

	
 
(defconst wg-version "1.1.1" "Current version of Workgroups.")
 

	
 
;;; customization
 

	
 
(defcustom wg-session-load-on-start (not (daemonp))
 
  "Load a session file on Workgroups start.
 
But only if Emacs is not started as daemon.  You don't want any
 
promts while Emacs is being started as daemon."
 
  :type 'boolean
 
  :group 'workgroups)
 
(defvaralias 'wg-use-default-session-file 'wg-session-load-on-start)
 

	
 
(defgroup workgroups nil
 
  "Workgroups for Emacs -- Emacs session manager"
 
  :group 'convenience)
 

	
 
(defcustom workgroups-mode nil
 
  "Non-nil if Workgroups mode is enabled."
 
  :set 'custom-set-minor-mode
 
  :initialize 'custom-initialize-default
 
  :group 'workgroups
 
  :type 'boolean)
 

	
 
(defcustom wg-first-wg-name "First workgroup"
 
  "Title of the first workgroup created."
 
  :type 'string
 
  :group 'workgroups)
 

	
 
(defcustom wg-modeline-string " wg"
 
  "Appears in modeline."
 
  :type 'string
 
  :group 'workgroups)
 

	
 
(defcustom wg-load-last-workgroup t
 
  "Load last active (not first) workgroup from all your workgroups if it exists."
 
  :group 'workgroups
 
  :type 'boolean)
 

	
 
(defcustom wg-control-frames t
 
  "Save/restore frames."
 
  :group 'workgroups
 
  :type 'boolean)
 

	
 

	
 
;; hooks
 

	
 
(defcustom workgroups-mode-hook nil
 
  "Hook run when `workgroups-mode' is turned on."
 
  :type 'hook
 
  :group 'workgroups)
 

	
 
(defcustom workgroups-mode-exit-hook nil
 
  "Hook run when `workgroups-mode' is turned off."
 
  :type 'hook
 
  :group 'workgroups)
 

	
 
(defcustom wg-switch-to-workgroup-hook nil
 
  "Hook run by `wg-switch-to-workgroup'."
 
  :type 'hook
 
  :group 'workgroups)
 

	
 
(defcustom wg-pre-window-configuration-change-hook nil
 
  "Hook run before any function that triggers
 
`window-configuration-change-hook'."
 
  :type 'hook
 
  :group 'workgroups)
 

	
 

	
 
(defcustom wg-open-this-wg nil
 
  "Try to open this workgroup on start.
 
If nil - nothing happens."
 
  :type 'string
 
  :group 'workgroups)
 

	
 
(defcustom wg-switch-to-first-workgroup-on-find-session-file t
 
  "Non-nil means switch to the first workgroup in a session file
 
when it's found with `wg-find-session-file'."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 

	
 

	
 

	
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
;;
 
;; FIXME:
 
;;
 
;; Only set `wg-workgroup-base-wconfig' on `wg-write-session-file' or
 
;; `delete-frame' and only with the most recently changed working-wconfig.
 
;; Then, since it's not overwritten on every call to
 
;; `wg-workgroup-working-wconfig', its restoration can be retried after manually
 
;; recreating buffers that couldn't be restored.  So it takes over the
 
;; 'incorrect restoration' portion of the base wconfig's duty.  All that leaves
 
;; to base wconfigs is that they're a saved wconfig the user felt was important.
 
;; So why not allow more of of them?  A workgroup could stash an unlimited
 
;; number of wconfigs.
 
;;
 
;; TODO:
 
;;
 
;;   * Write new commands for restoring stashed wconfigs
 
;;
 
;;   * Add this message on improper restoration of `base-wconfig':
 
;;
 
;;       "Unable to restore 'buf1', 'buf2'... Hit C-whatever to retry after
 
;;        manually recreating these buffers."
 
;;
 
;;
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 

	
 

	
 
;; workgroup restoration customization
 

	
 
;; TODO: possibly add `buffer-file-coding-system', `text-scale-mode-amount'
 
(defcustom wg-buffer-local-variables-alist
 
  `((major-mode nil wg-deserialize-buffer-major-mode)
 
    (mark-ring wg-serialize-buffer-mark-ring wg-deserialize-buffer-mark-ring)
 
    (left-fringe-width nil nil)
 
    (right-fringe-width nil nil)
 
    (fringes-outside-margins nil nil)
 
    (left-margin-width nil nil)
 
    (right-margin-width nil nil)
 
    (vertical-scroll-bar nil nil))
 
  "Alist mapping buffer-local variable symbols to serdes functions.
 

	
 
The `car' of each entry should be a buffer-local variable symbol.
 

	
 
The `cadr' of the entry should be either nil or a function of no
 
arguments.  If nil, the variable's value is used as-is, and
 
should have a readable printed representation.  If a function,
 
`funcall'ing it should yield a serialization of the value of the
 
variable.
 

	
 
The `caddr' of the entry should be either nil or a function of
 
one argument.  If nil, the serialized value from above is
 
assigned to the variable as-is.  It a function, `funcall'ing it
 
on the serialized value from above should do whatever is
 
necessary to properly restore the original value of the variable.
 
For example, in the case of `major-mode' it should funcall the
 
value (a major-mode function symbol) rather than just assigning
 
it to `major-mode'."
 
  :type 'alist
 
  :group 'workgroups)
 

	
 

	
 
(defcustom wg-nowg-string "No workgroups"
 
  "Display this string if there are no workgroups and
 
`wg-display-nowg' is t."
 
  :type 'string
 
  :group 'workgroups)
 

	
 
(defcustom wg-display-nowg nil
 
  "Display something if there are no workgroups."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
;; What to restore:
 

	
 
(defcustom wg-restore-remote-buffers t
 
  "Restore buffers that get \"t\" with `file-remote-p'."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-restore-frame-position t
 
  "Non-nil means restore frame position on workgroup restore."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-restore-scroll-bars t
 
  "Non-nil means restore scroll-bar settings on workgroup restore."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-restore-fringes t
 
  "Non-nil means restore fringe settings on workgroup restore."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-restore-margins t
 
  "Non-nil means restore margin settings on workgroup restore."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-restore-point t
 
  "Non-nil means restore `point' on workgroup restore.
 
This is included mainly so point restoration can be suspended
 
during `wg-morph' -- you probably want this non-nil."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-restore-point-max t
 
  "Controls point restoration when point is at `point-max'.
 
If `point' is at `point-max' when a wconfig is created, put
 
`point' back at `point-max' when the wconfig is restored, even if
 
`point-max' has increased in the meantime.  This is useful in,
 
say, irc buffers where `point-max' is constantly increasing."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-restore-mark t
 
  "Non-nil means restore mark data on workgroup restore."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-restore-window-dedicated-p t
 
  "Non-nil means restore `window-dedicated-p' on workgroup restore."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-remember-frame-for-each-wg nil
 
  "When switching workgroups - restore frame parameters for each workgroup.
 

	
 
When nil - save/restore frame parameters to/from the first workgroup."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 

	
 
(defcustom wg-wconfig-undo-list-max 20
 
  "Number of past window configs to retain for undo."
 
  :type 'integer
 
  :group 'workgroups)
 

	
 
(defcustom wg-wconfig-kill-ring-max 20
 
  "Maximum length of the `wg-wconfig-kill-ring'."
 
  :type 'integer
 
  :group 'workgroups)
 

	
 

	
 
;; buffer-list filtration customization
 

	
 
(defcustom wg-buffer-list-filtration-on t
 
  "Non-nil means Workgroups' buffer-list filtration feature is on.
 
Nil means ido and iswitchb behave normally.  See
 
`wg-buffer-list-filter-definitions' for more info."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-buffer-list-filter-definitions
 
  '((all "all" wg-buffer-list-filter-all)
 
    (fallback "fallback" nil))
 
  "List of buffer list filter definitions.
 
Each entry should be a list containing an identifier symbol, a
 
prompt string, and a function form that's funcall'd to produce
 
the filtered buffer-list.
 

	
 
The prompt string is displayed as part of the minibuffer prompt
 
when its filter is active.
 

	
 
The function form should be either a function-symbol or a lambda, and
 
should take two arguments: a workgroup and a list of live Emacs
 
buffers.  The function should return a new list of live buffers,
 
typically by filtering its second argument in some way.
 

	
 
Default buffer-list-filters include:
 

	
 
`all'           All buffer names
 

	
 
`fallback'      A special case used to fallback to the
 
                original (non-ido/iswitchb) Emacs command.
 
                `fallback' isn't actually a buffer-list-filter
 
                itself, but can be used in
 
                `wg-buffer-list-filter-order-alist' just the
 
                same.
 

	
 
Becomes workgroup-local when set with `wg-set-workgroup-parameter'.
 
Becomes session-local when set with `wg-set-session-parameter'."
 
  :type 'list
 
  :group 'workgroups)
 

	
 
(defcustom wg-buffer-list-filter-order-alist
 
  '((default all fallback))
 
  "Alist defining the order in which filtered buffer-lists are presented.
 

	
 
The car of each entry should be the symbol of the original Emacs
 
command (not the ido or iswitchb remappings) -- i.e. one of
0 comments (0 inline, 0 general)