Changeset - 3edbfb87fe7d
[Not reviewed]
0 5 0
Sergey Pashinin - 11 years ago 2014-07-01 19:44:58
sergey@pashinin.com
Save/restore frames (#11)

Probably works (for me) with usual file buffers
5 files changed with 75 insertions and 24 deletions:
0 comments (0 inline, 0 general)
src/workgroups-commands.el
Show inline comments
 
;;; workgroups-commands --- main commands
 
;;; Commentary:
 
;;; Code:
 

	
 
(require 'cl-lib)
 
(eval-when-compile
 
  (require 'ido)
 
  (require 'iswitchb))
 

	
 
(require 'ring)
 
(require 'workgroups-variables)
 
(require 'workgroups-utils-basic)
 
(require 'workgroups-pickel)
 
(require 'workgroups-functions)
 

	
 
;;; workgroup switching commands
 

	
 
(defun wg-switch-to-workgroup (workgroup &optional noerror)
 
  "Switch to WORKGROUP."
 
  (interactive (list (wg-read-workgroup-name)))
 
  ;; Set a parameter when using ECB
 
  ;; Mark if ECB is active
 
  (if (wg-current-workgroup t)
 
      (wg-set-workgroup-parameter (wg-current-workgroup t) 'ecb (and (boundp 'ecb-minor-mode)
 
                                                                     ecb-minor-mode)))
 
  ;;(wg-set-workgroup-parameter (wg-current-workgroup t) 'ecb-win-config (ecb-current-window-configuration))
 
  ;; (type-of (ecb-current-window-configuration))
 
  ;; (type-of (car (ecb-current-window-configuration)))
 
  ;; (type-of (car (nthcdr 3 (ecb-current-window-configuration))))
 
  ;; (wg-pickelable-or-error (ecb-current-window-configuration))
 
  ;;(ecb-current-window-configuration)
 
  ;;)
 
  (let ((workgroup (wg-get-workgroup-create workgroup))
 
        (current (wg-current-workgroup t)))
 
    (when (and (eq workgroup current) (not noerror))
 
      (error "Already on: %s" (wg-workgroup-name current)))
 
    (when current (push current wg-deactivation-list))
 
    (unwind-protect
 
        (progn
 
          ;; Before switching - turn off ECB
 
          ;; https://github.com/pashinin/workgroups2/issues/34
 
          (if (and (boundp 'ecb-minor-mode)
 
                   ecb-minor-mode
 
                   (equal ecb-frame (selected-frame)))
 
              (let ((ecb-split-edit-window-after-start 'before-deactivation))
 
                (ecb-deactivate)))
 

	
 
          (wg-restore-workgroup workgroup)
 
          (wg-set-previous-workgroup current)
 
          (wg-set-current-workgroup workgroup)
 

	
 
          ;; Save "last-workgroup" to the session params
 
          (if (and (wg-current-session t)
 
                   (wg-current-workgroup t))
 
              (wg-set-session-parameter (wg-current-session t)
 
                                        'last-workgroup
 
                                        (wg-workgroup-name (wg-current-workgroup))))
 

	
 
          ;; If a workgroup had ECB - turn it on
 
          (if (and (boundp 'ecb-minor-mode)
 
                   (not ecb-minor-mode)
 
                   (wg-workgroup-parameter (wg-current-workgroup t) 'ecb nil))
 
              (let ((ecb-split-edit-window-after-start 'before-deactivation))
 
                (ecb-activate)))
 
          ;;(ecb-last-window-config-before-deactivation
 
          ;; (wg-workgroup-parameter (wg-current-workgroup t) 'ecb-win-config nil)))
 

	
 
          (run-hooks 'wg-switch-to-workgroup-hook)
 
          (wg-fontified-message
 
            (:cmd "Switched: ")
 
            (wg-workgroup-name (wg-current-workgroup t))
 
            ))
 
      (when current (pop wg-deactivation-list)))))
 

	
 
(defun wg-switch-to-workgroup-other-frame (workgroup &optional n)
 
  "Switch to WORKGROUP in the frame N places cyclically from `selected-frame'.
 
Use `current-prefix-arg' for N if non-nil.  Otherwise N defaults to 1."
 
  (interactive (list (wg-read-workgroup-name) current-prefix-arg))
 
  (with-selected-frame (wg-cyclic-nth-from-frame (or n 1))
 
    (wg-switch-to-workgroup workgroup)))
 

	
 
(defun wg-switch-to-workgroup-at-index (index)
 
  "Switch to the workgroup at INDEX in `wg-workgroup-list'."
 
  (interactive (list (or current-prefix-arg (wg-read-workgroup-index))))
 
  (let ((wl (wg-workgroup-list-or-error)))
 
    (wg-switch-to-workgroup
 
     (or (nth index wl) (error "There are only %d workgroups" (length wl))))))
 

	
 
(cl-macrolet
 
    ((define-range-of-switch-to-workgroup-at-index (num)
 
       `(progn
 
          ,@(wg-docar (i (wg-range 0 num))
 
              `(defun ,(intern (format "wg-switch-to-workgroup-at-index-%d" i)) ()
 
                 ,(format "Switch to the workgroup at index %d." i)
 
                 (interactive)
 
                 (wg-switch-to-workgroup-at-index ,i))))))
 
  (define-range-of-switch-to-workgroup-at-index 10))
 

	
 
(defun wg-switch-to-cyclic-nth-from-workgroup (workgroup n)
 
  "Switch N workgroups cyclically from WORKGROUP in `wg-workgroup-list.'"
 
  (let ((workgroup-list (wg-workgroup-list-or-error))
 
        (workgroup (wg-get-workgroup workgroup t)))
 
    (wg-switch-to-workgroup
 
     (cond ((not workgroup) (car workgroup-list))
 
           ((= 1 (length workgroup-list)) (error "There's only one workgroup"))
 
           (t (wg-cyclic-nth-from-workgroup workgroup n))))))
 

	
 
(defun wg-switch-to-workgroup-left (&optional workgroup n)
 
  "Switch to the workgroup (- N) places from WORKGROUP in `wg-workgroup-list'.
 
Use `current-prefix-arg' for N if non-nil.  Otherwise N defaults to 1."
 
  (interactive (list nil current-prefix-arg))
 
  (wg-switch-to-cyclic-nth-from-workgroup workgroup (- (or n 1))))
 

	
 
(defun wg-switch-to-workgroup-right (&optional workgroup n)
 
  "Switch to the workgroup N places from WORKGROUP in `wg-workgroup-list'.
 
Use `current-prefix-arg' for N if non-nil.  Otherwise N defaults to 1."
 
  (interactive (list nil current-prefix-arg))
 
  (wg-switch-to-cyclic-nth-from-workgroup workgroup (or n 1)))
 

	
 
(defun wg-switch-to-workgroup-left-other-frame (&optional n)
 
  "Like `wg-switch-to-workgroup-left', but operates on the next frame."
 
  (interactive "p")
 
  (with-selected-frame (wg-cyclic-nth-from-frame (or n 1))
 
    (call-interactively 'wg-switch-to-workgroup-left)))
 

	
 
(defun wg-switch-to-workgroup-right-other-frame (&optional n)
 
  "Like `wg-switch-to-workgroup-right', but operates on the next frame."
 
  (interactive "p")
 
  (with-selected-frame (wg-cyclic-nth-from-frame (or n -1))
 
    (call-interactively 'wg-switch-to-workgroup-right)))
 

	
 
(defun wg-switch-to-previous-workgroup ()
 
  "Switch to the previous workgroup."
 
  (interactive)
 
  (wg-switch-to-workgroup (wg-previous-workgroup)))
 

	
 

	
 

	
 
;;; workgroup creation commands
 

	
 
(defun wg-create-workgroup (name &optional blank)
 
  "Create and add a workgroup named NAME.
 
Optional argument BLANK non-nil (set interactively with a prefix
 
arg) means use a blank, one window window-config.  Otherwise use
 
the current window-configuration.  Keep in mind that even though
 
the current window-config may be used, other parameters of the
 
current workgroup are not copied to the created workgroup.  For
 
that, use `wg-clone-workgroup'."
 
  (interactive (list (wg-read-new-workgroup-name) current-prefix-arg))
 
  (wg-switch-to-workgroup (wg-make-and-add-workgroup name blank))
 
  (wg-fontified-message
 
    (:cmd "Created: ")
 
    (:cur name) "  "
 
    (wg-workgroup-list-display)))
 

	
 
(defun wg-clone-workgroup (workgroup name)
 
  "Create and add a clone of WORKGROUP named NAME.
 
Keep in mind that only WORKGROUP's top-level alist structure is
 
copied, so destructive operations on the keys or values of
 
WORKGROUP will be reflected in the clone, and vice-versa.  Be
 
safe -- don't mutate them."
 
  (interactive (list nil (wg-read-new-workgroup-name)))
 
  (let* ((workgroup (wg-get-workgroup workgroup))
 
         (clone (wg-copy-workgroup workgroup)))
 
    (setf (wg-workgroup-name clone) name
 
          (wg-workgroup-uid clone) (wg-generate-uid))
 
    (when (wg-check-and-add-workgroup clone)
 
      (wg-flag-workgroup-modified clone))
 
    (wg-set-workgroup-working-wconfig
 
     clone (wg-workgroup-working-wconfig workgroup))
 
    (wg-switch-to-workgroup clone)
 
    (wg-fontified-message
 
      (:cmd "Cloned: ")
 
      (:cur (wg-workgroup-name workgroup))
 
      (:msg " to ")
 
      (:cur name) "  "
 
      (wg-workgroup-list-display))))
 

	
 

	
 

	
 
;;; workgroup killing commands
 

	
 
(defun wg-wconfig-kill-ring ()
 
  "Return `wg-wconfig-kill-ring', creating it first if necessary."
 
  (or wg-wconfig-kill-ring
 
      (setq wg-wconfig-kill-ring (make-ring wg-wconfig-kill-ring-max))))
 

	
 
(defun wg-add-to-wconfig-kill-ring (wconfig)
 
  "Add WCONFIG to `wg-wconfig-kill-ring'."
 
  (ring-insert (wg-wconfig-kill-ring) wconfig))
 

	
 
(defun wg-kill-workgroup (&optional workgroup)
 
  "Kill WORKGROUP, saving its working-wconfig to the kill ring."
 
  (interactive)
 
  (let* ((workgroup (wg-get-workgroup workgroup))
 
         (to (or (wg-previous-workgroup t)
 
                 (wg-cyclic-nth-from-workgroup workgroup))))
 
    (wg-add-to-wconfig-kill-ring (wg-workgroup-working-wconfig workgroup))
 
    (wg-delete-workgroup workgroup)
 
    (if (eq workgroup to) (wg-restore-wconfig (wg-make-blank-wconfig))
 
      (wg-switch-to-workgroup to))
 
    (wg-fontified-message
 
      (:cmd "Killed: ")
 
      (:cur (wg-workgroup-name workgroup)) "  "
 
      (wg-workgroup-list-display))))
 

	
 
(defun wg-kill-ring-save-base-wconfig (&optional workgroup)
 
  "Save WORKGROUP's base wconfig to the kill ring."
 
  (interactive)
 
  (let ((workgroup (wg-get-workgroup workgroup)))
 
    (wg-add-to-wconfig-kill-ring (wg-workgroup-base-wconfig workgroup))
 
    (wg-fontified-message
 
      (:cmd "Saved: ")
 
      (:cur (wg-workgroup-name workgroup))
 
      (:cur "'s ")
 
      (:msg "base wconfig to the kill ring"))))
 

	
 
(defun wg-kill-ring-save-working-wconfig (&optional workgroup)
 
  "Save WORKGROUP's working-wconfig to `wg-wconfig-kill-ring'."
 
  (interactive)
 
  (let ((workgroup (wg-get-workgroup workgroup)))
 
    (wg-add-to-wconfig-kill-ring (wg-workgroup-working-wconfig workgroup))
 
    (wg-fontified-message
 
      (:cmd "Saved: ")
 
      (:cur (wg-workgroup-name workgroup))
 
      (:cur "'s ")
 
      (:msg "working-wconfig to the kill ring"))))
 

	
 
(defun wg-yank-wconfig ()
 
  "Restore a wconfig from `wg-wconfig-kill-ring'.
 
Successive yanks restore wconfigs sequentially from the kill
 
ring, starting at the front."
 
  (interactive)
 
  (when (zerop (ring-length (wg-wconfig-kill-ring)))
 
    (error "The kill-ring is empty"))
 
  (let ((pos (if (not (eq real-last-command 'wg-yank-wconfig)) 0
 
               (1+ (or (get 'wg-yank-wconfig :position) 0)))))
 
    (put 'wg-yank-wconfig :position pos)
 
    (wg-restore-wconfig-undoably (ring-ref (wg-wconfig-kill-ring) pos))
 
    (wg-fontified-message
 
      (:cmd "Yanked: ")
 
      (:msg (format "%S" pos)) "  "
 
      (wg-workgroup-list-display))))
 

	
 
(defun wg-kill-workgroup-and-buffers (&optional workgroup)
 
  "Kill WORKGROUP and the buffers in its working-wconfig."
 
  (interactive)
 
  (let* ((workgroup (wg-get-workgroup workgroup))
 
         (bufs (save-window-excursion
 
                 (wg-restore-workgroup workgroup)
 
                 (mapcar #'window-buffer (window-list)))))
 
    (wg-kill-workgroup workgroup)
 
    (mapc #'kill-buffer bufs)
 
    (wg-fontified-message
 
      (:cmd "Killed: ")
 
      (:cur (wg-workgroup-name workgroup))
 
      (:msg " and its buffers ") "\n"
 
      (wg-workgroup-list-display))))
 

	
 
(defun wg-delete-other-workgroups (&optional workgroup)
 
  "Delete all workgroups but WORKGROUP."
 
  (interactive)
 
  (let ((workgroup (wg-get-workgroup workgroup)))
 
    (unless (or wg-no-confirm-on-destructive-operation
 
                (y-or-n-p "Really delete all other workgroups? "))
 
      (error "Cancelled"))
 
    (dolist (w (wg-workgroup-list-or-error))
 
      (unless (eq w workgroup)
 
        (wg-delete-workgroup w)))
 
    (unless (wg-current-workgroup-p workgroup)
 
      (wg-switch-to-workgroup workgroup))
 
    (wg-fontified-message
 
      (:cmd "Deleted: ")
 
      (:msg "All workgroups but ")
 
      (:cur (wg-workgroup-name workgroup)))))
 

	
 

	
 

	
 
;;; workgroup updating and reverting commands
 

	
 
(defun wg-revert-workgroup (&optional workgroup)
 
  "Restore WORKGROUP's window configuration to its state at the last save."
 
  (interactive)
 
  (let* ((workgroup (wg-get-workgroup workgroup))
 
         (base-wconfig (wg-workgroup-base-wconfig workgroup)))
 
    (if (wg-current-workgroup-p workgroup)
 
        (wg-restore-wconfig-undoably base-wconfig)
 
      (wg-add-wconfig-to-undo-list workgroup base-wconfig))
 
    (wg-fontified-message
 
      (:cmd "Reverted: ")
 
      (:cur (wg-workgroup-name workgroup)))))
 

	
 
(defun wg-revert-all-workgroups ()
 
  "Revert all workgroups to their base wconfigs.
 
Only workgroups' working-wconfigs in `selected-frame' are
 
reverted."
 
  (interactive)
 
  (mapc #'wg-revert-workgroup (wg-workgroup-list-or-error))
 
  (wg-fontified-message
 
    (:cmd "Reverted: ")
 
    (:msg "All")))
 

	
 

	
 

	
 
;;; saved wconfig commands
 

	
 
(defun wg-save-wconfig ()
 
  "Save the current wconfig to the current workgroup's saved wconfigs."
 
  (interactive)
 
  (let* ((workgroup (wg-current-workgroup))
 
         (name (wg-read-saved-wconfig-name workgroup))
 
         (wconfig (wg-current-wconfig)))
 
    (setf (wg-wconfig-name wconfig) name)
 
    (wg-workgroup-save-wconfig workgroup wconfig)
 
    (wg-fontified-message
 
      (:cmd "Saved: ")
 
      (:cur name))))
 

	
 
(defun wg-restore-saved-wconfig ()
 
  "Restore one of the current workgroup's saved wconfigs in `selected-frame'."
 
  (interactive)
 
  (let ((workgroup (wg-current-workgroup)))
 
    (wg-restore-wconfig-undoably
 
     (wg-workgroup-get-saved-wconfig
 
      workgroup
 
      (wg-completing-read
 
       "Saved wconfig: "
 
       (mapcar 'wg-wconfig-name (wg-workgroup-saved-wconfigs workgroup))
 
       nil t)))))
 

	
 
(defun wg-kill-saved-wconfig ()
 
  "Kill one of the current workgroup's saved wconfigs.
 
Also add it to the wconfig kill-ring."
 
  (interactive)
 
  (let* ((workgroup (wg-current-workgroup))
 
         (wconfig (wg-read-saved-wconfig workgroup)))
 
    (wg-workgroup-kill-saved-wconfig workgroup wconfig)
 
    (wg-add-to-wconfig-kill-ring wconfig)
 
    (wg-fontified-message
 
      (:cmd "Deleted: ")
 
      (:cur (wg-wconfig-name wconfig)))))
 

	
 

	
 

	
 
;;; workgroup-list reorganization commands
 

	
 
(defun wg-swap-workgroups ()
 
  "Swap the previous and current workgroups."
 
  (interactive)
 
  (wg-swap-workgroups-in-workgroup-list
 
   (wg-current-workgroup) (wg-previous-workgroup))
 
  (wg-fontified-message
 
    (:cmd "Swapped:  ")
 
    (wg-workgroup-list-display)))
 

	
 
(defun wg-offset-workgroup-left (&optional workgroup n)
 
  "Offset WORKGROUP leftward in `wg-workgroup-list' cyclically."
 
  (interactive (list nil current-prefix-arg))
 
  (wg-cyclic-offset-workgroup (wg-get-workgroup workgroup) (or n -1))
 
  (wg-fontified-message
 
    (:cmd "Offset left: ")
 
    (wg-workgroup-list-display)))
 

	
 
(defun wg-offset-workgroup-right (&optional workgroup n)
 
  "Offset WORKGROUP rightward in `wg-workgroup-list' cyclically."
 
  (interactive (list nil current-prefix-arg))
 
  (wg-cyclic-offset-workgroup (wg-get-workgroup workgroup) (or n 1))
 
  (wg-fontified-message
 
    (:cmd "Offset right: ")
 
    (wg-workgroup-list-display)))
 

	
 

	
 

	
 
;;; undo/redo commands
 

	
 
(defun wg-undo-wconfig-change (&optional workgroup)
 
  "Undo a change to the current workgroup's window-configuration."
 
  (interactive)
 
  (let* ((workgroup (wg-get-workgroup workgroup))
 
         (undid? (wg-workgroup-offset-position-in-undo-list workgroup 1)))
 
    (wg-fontified-message
 
      (:cmd "Undo: ")
 
      (wg-undo-timeline-display workgroup)
 
      (:cur (if undid? "" "  No more undo info")))))
 

	
 
(defun wg-redo-wconfig-change (&optional workgroup)
 
  "Redo a change to the current workgroup's window-configuration."
 
  (interactive)
 
  (let* ((workgroup (wg-get-workgroup workgroup))
 
         (redid? (wg-workgroup-offset-position-in-undo-list workgroup -1)))
 
    (wg-fontified-message
 
      (:cmd "Redo: ")
 
      (wg-undo-timeline-display workgroup)
 
      (:cur (if redid? "" "  No more redo info")))))
 

	
 
(defun wg-undo-once-all-workgroups ()
 
  "Do what the name says.  Useful for instance when you
 
accidentally call `wg-revert-all-workgroups' and want to return
 
all workgroups to their un-reverted state."
 
  (interactive)
 
  (mapc 'wg-undo-wconfig-change (wg-workgroup-list-or-error))
 
  (wg-message "Undid once on all workgroups."))
 

	
 
(defun wg-redo-once-all-workgroups ()
 
  "Do what the name says.  Probably useless.  Included for
 
symetry with `wg-undo-once-all-workgroups'."
 
  (interactive)
 
  (mapc 'wg-redo-wconfig-change (wg-workgroup-list-or-error))
 
  (wg-message "Redid once on all workgroups."))
 

	
 

	
 

	
 
;;; buffer-list-filter commands
 

	
 
(defun wg-switch-to-buffer ()
 
  "Workgroups' version of `switch-to-buffer'."
 
  (interactive)
 
  (wg-buffer-internal 'switch-to-buffer "Buffer"))
 

	
 
(defun wg-switch-to-buffer-other-window ()
 
  "Workgroups' version of `switch-to-buffer-other-window'."
 
  (interactive)
 
  (wg-buffer-internal
 
   'switch-to-buffer-other-window "Switch to buffer in other window"))
 

	
 
(defun wg-switch-to-buffer-other-frame ()
 
  "Workgroups' version of `switch-to-buffer-other-frame'."
 
  (interactive)
 
  (wg-buffer-internal
 
   'switch-to-buffer-other-frame "Switch to buffer in other frame"))
 

	
 
(defun wg-kill-buffer ()
 
  "Workgroups' version of `kill-buffer'."
 
  (interactive)
 
  (wg-buffer-internal
 
   'kill-buffer "Kill buffer" (buffer-name (current-buffer))))
 

	
 
(defun wg-display-buffer ()
 
  "Workgroups' version of `display-buffer'."
 
  (interactive)
 
  (wg-buffer-internal 'display-buffer "Display buffer"))
 

	
 
(defun wg-insert-buffer ()
 
  "Workgroups' version of `insert-buffer'."
 
  (interactive)
 
  (wg-buffer-internal 'insert-buffer "Insert buffer"))
 

	
 
;; FIXME: If you C-h i for info, then wg-next-buffer, you occasionally don't
 
;; switch to the buffer you were on previously.
 
(defun wg-next-buffer-internal (buffer-list &optional prev noerror)
 
  "Switch to the next buffer in Workgroups' filtered buffer list."
 
  (when buffer-list
 
    (let* ((cur (current-buffer))
 
           (next (or (wg-cyclic-nth-from-elt cur buffer-list (if prev -1 1))
 
                     (car buffer-list))))
 
      (unless (eq cur next)
 
        (switch-to-buffer next)
 
        (unless prev (bury-buffer cur))
 
        next))))
 

	
 
(defun wg-next-buffer (&optional prev)
 
  "Switch to the next buffer in Workgroups' filtered buffer list.
 
In the post-command message the current buffer is rotated to the
 
middle of the list to more easily see where `wg-previous-buffer'
 
will take you."
 
  (interactive)
 
  (let ((command (if prev 'previous-buffer 'next-buffer)))
 
    (if (not (wg-filter-buffer-list-p))
 
        (call-interactively (wg-prior-mapping workgroups-mode command))
 
      (wg-with-buffer-list-filters command
 
        (wg-awhen (wg-filtered-buffer-list) (wg-next-buffer-internal it prev))
 
        (wg-message (wg-buffer-command-display))))))
 

	
 
(defun wg-previous-buffer ()
 
  "Switch to the next buffer in Workgroups' filtered buffer list."
 
  (interactive)
 
  (wg-next-buffer t))
 

	
 
(defun wg-bury-buffer (&optional buffer-or-name)
 
  "Remove BUFFER-OR-NAME from the current workgroup, bury it,
 
and switch to the next buffer in the buffer-list-filter."
 
  (interactive (list (current-buffer)))
 
  (if (not (wg-filter-buffer-list-p))
 
      (call-interactively (wg-prior-mapping workgroups-mode 'bury-buffer))
 
    (wg-with-buffer-list-filters 'bury-buffer
 
      (wg-next-buffer-internal (wg-filtered-buffer-list))
 
      (bury-buffer buffer-or-name)
 
      (wg-message (wg-buffer-command-display)))))
 

	
 
(defun wg-banish-buffer (&optional buffer-or-name)
 
  "Dissociate BUFFER-OR-NAME from the current workgroup, and bury it."
 
  (interactive)
 
  (let ((buffer (or buffer-or-name (current-buffer))))
 
    (wg-workgroup-dissociate-bufobj (wg-current-workgroup) buffer)
 
    (wg-bury-buffer buffer)))
 

	
 
(defun wg-associate-buffer-with-workgroup (&optional workgroup buffer weak)
 
  "Associate BUFFER with WORKGROUP.
 
WEAK non-nil means weakly associate BUFFER."
 
  (interactive (list nil nil current-prefix-arg))
 
  (let* ((workgroup (wg-get-workgroup workgroup))
 
         (buffer (or buffer (current-buffer)))
 
         (bname (buffer-name buffer))
 
         (wgname (wg-workgroup-name workgroup)))
 
    (if (wg-workgroup-associate-bufobj workgroup buffer weak)
 
        (wg-message "%s-associated %S with %s"
 
                    (if weak "Weakly" "Strongly") bname wgname)
 
      (wg-message "%S is already associated with %s" bname wgname))))
 

	
 
(defun wg-associate-visible-buffers-with-workgroup (&optional workgroup weak)
 
  "Associate all buffers visible in `selected-frame' with WORKGROUP.
 
WEAK non-nil means weakly associate them.  Otherwise strongly
 
associate them."
 
  (interactive (list nil current-prefix-arg))
 
  (let ((workgroup (wg-get-workgroup workgroup))
 
        (buffers (mapcar 'window-buffer (window-list))))
 
    (dolist (buffer buffers)
 
      (wg-workgroup-associate-bufobj workgroup buffer weak))
 
    (wg-fontified-message
 
      (:cmd (format "%s associated: " (if weak "Weakly" "Strongly")))
 
      (wg-buffer-list-display buffers))))
 

	
 
(defun wg-dissociate-buffer-from-workgroup (&optional workgroup buffer)
 
  "Dissociate BUFFER from WORKGROUP."
 
  (interactive (list nil nil))
 
  (let ((workgroup (wg-get-workgroup workgroup))
 
        (buffer (or buffer (current-buffer))))
 
    (wg-message
 
     (if (wg-workgroup-dissociate-bufobj workgroup buffer)
 
         "Dissociated %S from %s" "%S isn't associated with %s")
 
     (wg-buffer-name buffer)
 
     (wg-workgroup-name workgroup))))
 

	
 
(defun wg-restore-workgroup-associated-buffers (&optional workgroup)
 
  "Restore all the buffers associated with WORKGROUP that can be restored."
 
  (interactive)
 
  (let* ((workgroup (wg-get-workgroup workgroup))
 
         (restored-buffers (wg-restore-workgroup-associated-buffers-internal
 
                            workgroup)))
 
    (wg-fontified-message
 
      (:cmd "Restored: ")
 
      (wg-buffer-list-display restored-buffers))))
 

	
 
(defun wg-cycle-buffer-association-type ()
 
  "Cycle the current buffer's association type in the current workgroup.
 
See `wg-workgroup-cycle-bufobj-association-type' for details."
 
  (interactive)
 
  (let* ((workgroup (wg-current-workgroup))
 
         (buffer (current-buffer))
 
         (type (wg-workgroup-cycle-bufobj-association-type workgroup buffer)))
 
    (force-mode-line-update)
 
    (wg-fontified-message
 
      (:cur (buffer-name buffer))
 
      (:cmd (cl-case type
 
              (strong " strongly associated with ")
 
              (weak " weakly associated with ")
 
              (otherwise " unassociated with ")))
 
      (:cur (wg-workgroup-name workgroup)))))
 

	
 
(defun wg-dissociate-weakly-associated-buffers (&optional workgroup)
 
  "Dissociate from the current workgroup all weakly associated buffers."
 
  (interactive)
 
  (let ((workgroup (wg-get-workgroup workgroup)))
 
    (wg-workgroup-dissociate-weakly-associated-buffers workgroup)
 
    (wg-fontified-message
 
      (:cmd "Remaining buffers: ")
 
      (wg-buffer-list-display (wg-workgroup-associated-buffers workgroup)))))
 

	
 

	
 

	
 
;;; window-tree commands
 
;;
 
;; TODO: These are half-hearted.  Clean them up; allow specification of the
 
;; window-tree depth at which to operate; add complex window creation commands;
 
;; and add window splitting, deletion and locking commands.
 

	
 
(defun wg-transpose-window-internal (workgroup offset)
 
  "Move `selected-window' by OFFSET in its wlist."
 
  (wg-restore-wconfig-undoably
 
   (wg-wconfig-move-window
 
    (wg-workgroup-working-wconfig
 
     (wg-get-workgroup workgroup))
 
    offset)))
 

	
 
(defun wg-backward-transpose-window (&optional workgroup offset)
 
  "Move `selected-window' backward by OFFSET in its wlist."
 
  (interactive (list nil current-prefix-arg))
 
  (wg-transpose-window-internal workgroup (or offset -1)))
 

	
 
(defun wg-transpose-window (&optional workgroup offset)
 
  "Move `selected-window' forward by OFFSET in its wlist."
 
  (interactive (list nil current-prefix-arg))
 
  (wg-transpose-window-internal workgroup (or offset 1)))
 

	
 
(defun wg-reverse-frame-horizontally (&optional workgroup)
 
  "Reverse the order of all horizontally split wtrees."
 
  (interactive)
 
  (wg-restore-wconfig-undoably
 
   (wg-reverse-wconfig
 
    (wg-workgroup-working-wconfig
 
     (wg-get-workgroup workgroup)))))
 

	
 
(defun wg-reverse-frame-vertically (&optional workgroup)
 
  "Reverse the order of all vertically split wtrees."
 
  (interactive)
 
  (wg-restore-wconfig-undoably
 
   (wg-reverse-wconfig
 
    (wg-workgroup-working-wconfig
 
     (wg-get-workgroup workgroup))
 
    t)))
 

	
 
(defun wg-reverse-frame-horizontally-and-vertically (&optional workgroup)
 
  "Reverse the order of all wtrees."
 
  (interactive)
 
  (wg-restore-wconfig-undoably
 
   (wg-reverse-wconfig
 
    (wg-workgroup-working-wconfig
 
     (wg-get-workgroup workgroup))
 
    'both)))
 

	
 
(defun wg-toggle-window-dedicated-p ()
 
  "Toggle `window-dedicated-p' in `selected-window'."
 
  (interactive)
 
  (set-window-dedicated-p nil (not (window-dedicated-p)))
 
  (force-mode-line-update t)
 
  (wg-fontified-message
 
    (:cmd "Window:")
 
    (:cur (concat (unless (window-dedicated-p) " not") " dedicated"))))
 

	
 

	
 

	
 
;;; misc commands
 

	
 
(defun wg-rename-workgroup (workgroup newname)
 
  "Rename WORKGROUP to NEWNAME."
 
  (interactive (list nil (wg-read-new-workgroup-name "New name: ")))
 
  (let* ((workgroup (wg-get-workgroup workgroup))
 
         (oldname (wg-workgroup-name workgroup)))
 
    (setf (wg-workgroup-name workgroup) newname)
 
    (wg-flag-workgroup-modified workgroup)
 
    (wg-fontified-message
 
      (:cmd "Renamed: ")
 
      (:cur oldname)
 
      (:msg " to ")
 
      (:cur (wg-workgroup-name workgroup)))))
 

	
 
(defun wg-reset (&optional force)
 
  "Reset Workgroups.
 
Resets all frame parameters, buffer-local vars, the current
 
Workgroups session object, etc."
 
  (interactive "P")
 
  (unless (or force wg-no-confirm-on-destructive-operation
 
              (y-or-n-p "Really reset Workgroups? "))
 
    (error "Canceled"))
 
  (wg-reset-internal)
 
  (wg-fontified-message
 
    (:cmd "Reset: ")
 
    (:msg "Workgroups")))
 

	
 

	
 

	
 
;;; file commands
 

	
 
(defun wg-read-session-save-file-name ()
 
  "Read and return a new session filename."
 
  (read-file-name "Save session as: "))
 

	
 
(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 (wg-read-session-save-file-name)
 
                     (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)))
 

	
 
(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-use-default-session-file wg-default-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)
 
         (wg-read-session-save-file-name)))))
 

	
 
(defun wg-query-and-save-if-modified ()
 
  "Query for save when `wg-modified-p'."
 
  (or (not (wg-modified-p))
 
      (when (y-or-n-p "Save modified workgroups? ")
 
        (wg-save-session))))
 

	
 
(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)
 
            (if (string-equal "initial_terminal" (terminal-name frame))
 
                (delete frame fl))) fl)
 
    (setq fl (delete (selected-frame) fl))
 
    (if (wg-current-session t)
 
          (wg-set-session-parameter (wg-current-session t)
 
                                    'frame-list
 
                                    (mapcar 'wg-frame-to-wconfig fl)))))
 

	
 
(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 (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)")))))
 

	
 
(defun wg-find-file-in-new-workgroup (filename)
 
  "Create a new blank workgroup and find file FILENAME in it."
 
  (interactive "FFind file in new workgroup: ")
 
  (wg-create-workgroup (file-name-nondirectory filename) t)
 
  (find-file filename))
 

	
 
(defun wg-find-file-read-only-in-new-workgroup (filename)
 
  "Create a new workgroup and find file FILENAME read-only in it."
 
  (interactive "FFind file read only in new workgroup: ")
 
  (wg-create-workgroup (file-name-nondirectory filename) t)
 
  (find-file-read-only filename))
 

	
 
(defun wg-dired-in-new-workgroup (dirname &optional switches)
 
  "Create a workgroup and open DIRNAME in dired with SWITCHES."
 
  (interactive (list (read-directory-name "Dired (directory): ")
 
                     current-prefix-arg))
 
  (wg-create-workgroup dirname)
 
  (dired dirname switches))
 

	
 

	
 

	
 
;;; toggle commands
 

	
 
(defun wg-toggle-and-message (symbol)
 
  "Toggle SYMBOL's truthiness and message the new value."
 
  (wg-fontified-message
 
    (:cmd (format "%s: " symbol))
 
    (:msg (format "%s" (wg-toggle symbol)))))
 

	
 
(defun wg-toggle-buffer-list-filtration ()
 
  "Toggle `wg-buffer-list-filtration-on'."
 
  (interactive)
 
  (wg-toggle-and-message 'wg-buffer-list-filtration-on))
 

	
 
(defun wg-toggle-mode-line-display ()
 
  "Toggle `wg-mode-line-display-on'."
 
  (interactive)
 
  (wg-toggle-and-message 'wg-mode-line-display-on))
 

	
 

	
 

	
 
;;; echo commands
 

	
 
(defun wg-echo-current-workgroup ()
 
  "Display the name of the current workgroup in the echo area."
 
  (interactive)
 
  (wg-fontified-message
 
    (:cmd "Current: ")
 
    (:cur (wg-workgroup-name (wg-current-workgroup)))))
 

	
 
(defun wg-echo-all-workgroups ()
 
  "Display the names of all workgroups in the echo area."
 
  (interactive)
 
  (wg-fontified-message
 
    (:cmd "Workgroups: ")
 
    (wg-workgroup-list-display)))
 

	
 
(defun wg-echo-time ()
 
  "Echo the current time.  Optionally includes `battery' info."
 
  (interactive)
 
  (wg-message ;; Pass through format to escape the % in `battery'
 
   "%s" (wg-fontify
 
          (:cmd "Current time: ")
 
          (:msg (format-time-string wg-time-format))
 
          (when (and wg-display-battery (fboundp 'battery))
 
            (wg-fontify "\n" (:cmd "Battery: ") (:msg (battery)))))))
 

	
 
(defun wg-echo-version ()
 
  "Echo Workgroups' current version number."
 
  (interactive)
 
  (wg-fontified-message
 
    (:cmd "Workgroups version: ")
 
    (:msg wg-version)))
 

	
 
(defun wg-echo-last-message ()
 
  "Echo the last message Workgroups sent to the echo area.
 
The string is passed through a format arg to escape %'s."
 
  (interactive)
 
  (message "%s" wg-last-message))
 

	
 

	
 

	
 
;;; help commands
 

	
 
(defun wg-help ()
 
  "Just call `apropos-command' on \"^wg-\".
 
There used to be a bunch of help-buffer construction stuff here,
 
including a `wg-help' variable that basically duplicated every
 
command's docstring;  But why, when there's `apropos-command'?"
 
  (interactive)
 
  (apropos-command "^wg-"))
 

	
 

	
 
(require 'workgroups-commands-minibuffer)
 

	
 
(provide 'workgroups-commands)
src/workgroups-pickel.el
Show inline comments
 
;;; workgroups-pickel.el --- Elisp object serdes used by Workgroups
 
;;
 
;; Copyright (C) 2010, 2011 tlh
 
;;
 
;; Author: tlh <thunkout at gmail dot com>
 
;; Keywords: serialization deserialization serdes
 
;; Homepage: https://github.com/tlh/workgroups.el
 
;; Version   1.0.0
 

	
 
;; This program is free software; you can redistribute it and/or modify
 
;; it under the terms of the GNU General Public License as published by
 
;; the Free Software Foundation; either version 2 of the License, or (at
 
;; your option) any later version.
 

	
 
;; This program is distributed in the hope that it will be useful, but
 
;; WITHOUT ANY WARRANTY; without even the implied warranty of
 
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
;; General Public License for more details.
 

	
 
;; You should have received a copy of the GNU General Public License
 
;; along with this program; if not, write to the Free Software
 
;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 
;; USA
 

	
 
;;; Commentary:
 
;;
 
;;; Code:
 

	
 
(require 'cl-lib)
 
(require 'workgroups-utils-basic)
 

	
 

	
 
;;; vars
 

	
 
(defvar wg-pickel-identifier '~pickel!~
 
  "Symbol identifying a stream as a pickel.")
 

	
 
(defvar wg-pickel-pickelable-types
 
  '(integer
 
    float
 
    symbol
 
    string
 
    cons
 
    vector
 
    hash-table
 
    buffer
 
    ;;window-configuration
 
    ;;frame
 
    ;;window
 
    ;;process
 
    )
 
  "Types pickel can serialize.")
 

	
 
(defvar wg-pickel-object-serializers
 
  '((integer    . identity)
 
    (float      . identity)
 
    (string     . identity)
 
    (symbol     . wg-pickel-symbol-serializer)
 
    (cons       . wg-pickel-cons-serializer)
 
    (vector     . wg-pickel-vector-serializer)
 
    (hash-table . wg-pickel-hash-table-serializer)
 
    ;;(window-configuration   . wg-pickel-window-configuration-serializer)
 
    (buffer     . wg-pickel-buffer-serializer))
 
  "Alist mapping types to object serialization functions.")
 

	
 
(defvar wg-pickel-link-serializers
 
  '((cons       . wg-pickel-cons-link-serializer)
 
    (vector     . wg-pickel-vector-link-serializer)
 
    (hash-table . wg-pickel-hash-table-link-serializer))
 
  "Alist mapping types to link serialization functions.")
 

	
 
(defvar wg-pickel-object-deserializers
 
  '((s . wg-pickel-deserialize-uninterned-symbol)
 
    (c . wg-pickel-deserialize-cons)
 
    (v . wg-pickel-deserialize-vector)
 
    (h . wg-pickel-deserialize-hash-table)
 
    (b . wg-pickel-deserialize-buffer))
 
  ;; (f . wg-pickel-deserialize-frame))
 
  "Alist mapping type keys to object deserialization functions.")
 

	
 
(defvar wg-pickel-link-deserializers
 
  `((c . wg-pickel-cons-link-deserializer)
 
    (v . wg-pickel-vector-link-deserializer)
 
    (h . wg-pickel-hash-table-link-deserializer))
 
  "Alist mapping type keys to link deserialization functions.")
 

	
 

	
 

	
 
;;; errors and predicates
 

	
 
(put 'wg-pickel-unpickelable-type-error
 
     'error-conditions
 
     '(error wg-pickel-errors wg-pickel-unpickelable-type-error))
 

	
 
(put 'wg-pickel-unpickelable-type-error
 
     'error-message
 
     "Attemp to pickel unpickelable type")
 

	
 
(defun wg-pickelable-or-error (obj)
 
  "Error when OBJ isn't pickelable."
 
  (unless (memq (type-of obj) wg-pickel-pickelable-types)
 
    (signal 'wg-pickel-unpickelable-type-error
 
            (format "Can't pickel objects of type: %S" (type-of obj))))
 
  (cl-typecase obj
 
    (cons
 
     (wg-pickelable-or-error (car obj))
 
     (wg-pickelable-or-error (cdr obj)))
 
    (vector
 
     (cl-map nil 'wg-pickelable-or-error obj))
 
    (hash-table
 
     (wg-dohash (key value obj)
 
       (wg-pickelable-or-error key)
 
       (wg-pickelable-or-error value)))))
 

	
 
(defun wg-pickelable-p (obj)
 
  (condition-case err
 
      (progn (wg-pickelable-or-error obj) t)
 
    (wg-pickel-unpickelable-type-error nil)))
 

	
 
(defun wg-pickel-p (obj)
 
  "Return t when OBJ is a pickel, nil otherwise."
 
  (and (consp obj) (eq (car obj) wg-pickel-identifier)))
 

	
 

	
 

	
 
;; accessor functions
 

	
 
(defun wg-pickel-object-serializer (obj)
 
  "Return the object serializer for the `type-of' OBJ."
 
  (or (wg-aget wg-pickel-object-serializers (type-of obj))
 
      (error "Invalid type: %S" (type-of obj))))
 

	
 
(defun wg-pickel-link-serializer (obj)
 
  "Return the link serializer for the `type-of' OBJ."
 
  (wg-aget wg-pickel-link-serializers (type-of obj)))
 

	
 
(defun wg-pickel-object-deserializer (key)
 
  "Return the object deserializer for type key KEY, or error."
 
  (or (wg-aget wg-pickel-object-deserializers key)
 
      (error "Invalid object deserializer key: %S" key)))
 

	
 
(defun wg-pickel-link-deserializer (key)
 
  "Return the link deserializer for type key KEY, or error."
 
  (or (wg-aget wg-pickel-link-deserializers key)
 
      (error "Invalid link deserializer key: %S" key)))
 

	
 

	
 

	
 
;;; bindings
 

	
 
(defun wg-pickel-make-bindings-table (obj)
 
  "Return a table binding unique subobjects of OBJ to ids."
 
  (let ((binds (make-hash-table :test 'eq))
 
        (id -1))
 
    (cl-labels
 
     ((inner (obj)
 
           (unless (gethash obj binds)
 
              (puthash obj (cl-incf id) binds)
 
              (cl-case (type-of obj)
 
                (cons
 
                 (inner (car obj))
 
                 (inner (cdr obj)))
 
                (vector
 
                 (dotimes (idx (length obj))
 
                   (inner (aref obj idx))))
 
                (hash-table
 
                 (wg-dohash (key val obj)
 
                   (inner key)
 
                   (inner val)))))))
 
      (inner obj)
 
      binds)))
 

	
 

	
 

	
 
;;; object serialization
 

	
 
(defun wg-pickel-symbol-serializer (symbol)
 
  "Return SYMBOL's serialization."
 
  (cond ((eq symbol t) t)
 
        ((eq symbol nil) nil)
 
        ((intern-soft symbol) symbol)
 
        (t (list 's (symbol-name symbol)))))
 

	
 
(defun wg-pickel-cons-serializer (cons)
 
  "Return CONS's serialization."
 
  (list 'c))
 

	
 
(defun wg-pickel-vector-serializer (vector)
 
  "Return VECTOR's serialization."
 
  (list 'v (length vector)))
 

	
 
(defun wg-pickel-hash-table-serializer (table)
 
  "Return HASH-TABLE's serialization."
 
  (list 'h
 
        (hash-table-test table)
 
        (hash-table-size table)
 
        (hash-table-rehash-size table)
 
        (hash-table-rehash-threshold table)
 
        (hash-table-weakness table)))
 

	
 
(defun wg-pickel-window-configuration-serializer (wc)
 
  "Return Window configuration WC's serialization."
 
  (list 'wc
 
        1))
 

	
 
(defun wg-pickel-buffer-serializer (buffer)
 
  "Return BUFFER's UID in workgroups buffer list."
 
  (list 'b (wg-add-buffer-to-buf-list buffer)))
 

	
 
(defun wg-pickel-serialize-objects (binds)
 
  "Return a list of serializations of the objects in BINDS."
 
  (let (result)
 
    (wg-dohash (obj id binds result)
 
      (setq result
 
            (nconc (list id (funcall (wg-pickel-object-serializer obj) obj))
 
                   result)))))
 

	
 

	
 

	
 
;;; link serialization
 

	
 
(defun wg-pickel-cons-link-serializer (cons binds)
 
  "Return the serialization of CONS's links in BINDS."
 
  (list 'c
 
        (gethash cons binds)
 
        (gethash (car cons) binds)
 
        (gethash (cdr cons) binds)))
 

	
 
(defun wg-pickel-vector-link-serializer (vector binds)
 
  "Return the serialization of VECTOR's links in BINDS."
 
  (let (result)
 
    (dotimes (i (length vector) result)
 
      (setq result
 
            (nconc (list 'v
 
                         (gethash vector binds)
 
                         i
 
                         (gethash (aref vector i) binds))
 
                   result)))))
 

	
 
(defun wg-pickel-hash-table-link-serializer (table binds)
 
  "Return the serialization of TABLE's links in BINDS."
 
  (let (result)
 
    (wg-dohash (key value table result)
 
      (setq result
 
            (nconc (list 'h
 
                         (gethash key binds)
 
                         (gethash value binds)
 
                         (gethash table binds))
 
                   result)))))
 

	
 
(defun wg-pickel-serialize-links (binds)
 
  "Return a list of serializations of the links between objects in BINDS."
 
  (let (result)
 
    (wg-dohash (obj id binds result)
 
      (wg-awhen (wg-pickel-link-serializer obj)
 
        (setq result (nconc (funcall it obj binds) result))))))
 

	
 

	
 

	
 
;;; object deserialization
 

	
 
(defun wg-pickel-deserialize-uninterned-symbol (name)
 
  "Return a new uninterned symbol from NAME."
 
  (make-symbol name))
 

	
 
(defun wg-pickel-deserialize-cons ()
 
  "Return a new cons cell initialized to nil."
 
  (cons nil nil))
 

	
 
(defun wg-pickel-deserialize-vector (length)
 
  "Return a new vector of length LENGTH."
 
  (make-vector length nil))
 

	
 
(defun wg-pickel-deserialize-hash-table (test size rsize rthresh weakness)
 
  "Return a new hash-table with the specified properties."
 
  (make-hash-table :test test :size size :rehash-size rsize
 
                   :rehash-threshold rthresh :weakness weakness))
 

	
 
(defun wg-pickel-deserialize-buffer (uid)
 
  "Return a restored buffer from it's UID."
 
  (wg-restore-buffer (wg-find-buf-by-uid uid)))
 

	
 
(defun wg-pickel-deserialize-objects (serial-objects)
 
  "Return a hash-table of objects deserialized from SERIAL-OBJECTS."
 
  (let ((binds (make-hash-table)))
 
    (wg-destructuring-dolist ((id obj . rest) serial-objects binds)
 
      (puthash id
 
               (if (atom obj) obj
 
                 (wg-dbind (key . data) obj
 
                   (apply (wg-pickel-object-deserializer key) data)))
 
               binds))))
 

	
 

	
 

	
 
;;; link deserialization
 

	
 
(defun wg-pickel-cons-link-deserializer (cons-id car-id cdr-id binds)
 
  "Relink a cons cell with its car and cdr in BINDS."
 
  (let ((cons (gethash cons-id binds)))
 
    (setcar cons (gethash car-id binds))
 
    (setcdr cons (gethash cdr-id binds))))
 

	
 
(defun wg-pickel-vector-link-deserializer (vector-id index value-id binds)
 
  "Relink a vector with its elements in BINDS."
 
  (aset (gethash vector-id binds) index (gethash value-id binds)))
 

	
 
(defun wg-pickel-hash-table-link-deserializer (key-id value-id table-id binds)
 
  "Relink a hash-table with its keys and values in BINDS."
 
  (puthash (gethash key-id binds)
 
           (gethash value-id binds)
 
           (gethash table-id binds)))
 

	
 
(defun wg-pickel-deserialize-links (serial-links binds)
 
  "Return BINDS after relinking all its objects according to SERIAL-LINKS."
 
  (wg-destructuring-dolist ((key arg1 arg2 arg3 . rest) serial-links binds)
 
    (funcall (wg-pickel-link-deserializer key) arg1 arg2 arg3 binds)))
 

	
 

	
 

	
 
;;; pickeling
 

	
 
(defun wg-pickel (obj)
 
  "Return the serialization of OBJ."
 
  (wg-pickelable-or-error obj)
 
  (let ((binds (wg-pickel-make-bindings-table obj)))
 
    (list wg-pickel-identifier
 
          (wg-pickel-serialize-objects binds)
 
          (wg-pickel-serialize-links binds)
 
          (gethash obj binds))))
 

	
 
(defun wg-pickel-to-string (obj)
 
  "Serialize OBJ to a string and return the string."
 
  (format "%S" (wg-pickel obj)))
 

	
 
(defun wg-pickel-to-file (file obj)
 
  "Serialize OBJ to FILE."
 
  (wg-write-sexp-to-file (wg-pickel obj) file))
 

	
 

	
 

	
 
;;; unpickeling
 

	
 
(defun wg-unpickel (pickel)
 
  "Return the deserialization of PICKEL."
 
  (unless (wg-pickel-p pickel)
 
    (error "Attempt to unpickel a non-pickel."))
 
  (wg-dbind (id serial-objects serial-links result) pickel
 
    (gethash
 
     result
 
     (wg-pickel-deserialize-links
 
      serial-links
 
      (wg-pickel-deserialize-objects serial-objects)))))
 

	
 
(defun wg-unpickel-file (file)
 
  "`unpickel' an object directly from FILE."
 
  (wg-unpickel (wg-lisp-object-from-file file)))
 

	
 
(defun wg-unpickel-string (str)
 
  "`unpickel' and object directly from STR."
 
  (wg-unpickel (read str)))
 

	
 

	
 

	
 

	
 

	
 
;;; parameter pickeling
 

	
 
  (defun wg-pickel-workgroup-parameters (workgroup)
 
    "If WORKGROUP's parameters are non-nil, return a copy of
 
WORKGROUP after pickeling its parameters. Otherwise return
 
WORKGROUP."
 
    (if (not (wg-workgroup-parameters workgroup)) workgroup
 
      (let ((copy (wg-copy-workgroup workgroup)))
 
        (wg-asetf (wg-workgroup-parameters copy) (wg-pickel it))
 
        copy)))
 

	
 
  (defun wg-unpickel-workgroup-parameters (workgroup)
 
    "If WORKGROUP's parameters are non-nil, return a copy of
 
WORKGROUP after unpickeling its parameters. Otherwise return
 
WORKGROUP."
 
    (if (not (wg-workgroup-parameters workgroup)) workgroup
 
      (let ((copy (wg-copy-workgroup workgroup)))
 
        (wg-asetf (wg-workgroup-parameters copy) (wg-unpickel it))
 
        copy)))
 

	
 
  (defun wg-pickel-all-session-parameters (session)
 
    "Return a copy of SESSION after pickeling its
 
parameters and the parameters of all its workgroups."
 
    (let ((copy (wg-copy-session session)))
 
      (when (wg-session-parameters copy)
 
        (wg-asetf (wg-session-parameters copy) (wg-pickel it)))
 
      (wg-asetf (wg-session-workgroup-list copy)
 
                (cl-mapcar 'wg-pickel-workgroup-parameters it))
 
      copy))
 

	
 
  (defun wg-unpickel-session-parameters (session)
 
    "Return a copy of SESSION after unpickeling its
 
parameters and the parameters of all its workgroups."
 
    (let ((copy (wg-copy-session session)))
 
      (when (wg-session-parameters copy)
 
        (wg-asetf (wg-session-parameters copy) (wg-unpickel it)))
 
      (wg-asetf (wg-session-workgroup-list copy)
 
                (cl-mapcar 'wg-unpickel-workgroup-parameters it))
 
      copy))
 

	
 
(provide 'workgroups-pickel)
 
;;; workgroups-pickel.el ends here
src/workgroups-restore.el
Show inline comments
 
;;; workgroups-restore --- Functions to restore buffers and frames
 
;;; Commentary:
 
;;
 
;; TIPS
 
;;---------
 
;; Each Emacs frame ("window") can contain several workgroups.
 
;; WCONFIG is settings for each workgroup (buffers, parameters,...)
 
;;
 
;; So restoring WCONFIG using `wg-restore-wconfig' is restoring buffers
 
;; for current workgroup. Generally speaking each Workgroup can have
 
;; several WCONFIGs.
 
;;
 
;;; Code:
 

	
 
(require 'workgroups-variables)
 

	
 
(defun wg-restore-default-buffer ()
 
  "Switch to `wg-default-buffer'."
 
  (switch-to-buffer wg-default-buffer t))
 

	
 
(defun wg-restore-existing-buffer (buf)
 
  "Switch to and return BUF's referrent (some live buffer) if it exists."
 
  (wg-awhen (wg-find-buf-in-buffer-list buf (buffer-list))
 
    (switch-to-buffer it t)
 
    (wg-set-buffer-uid-or-error (wg-buf-uid buf))
 
    it))
 

	
 
(defun wg-restore-file-buffer (buf)
 
  "Restore BUF by finding its file.  Return the created buffer.
 
If BUF's file doesn't exist, call `wg-restore-default-buffer'"
 
  (wg-when-let ((file-name (wg-buf-file-name buf)))
 
    (when (or wg-restore-remote-buffers
 
              (not (file-remote-p file-name)))
 
      (cond ((file-exists-p file-name)
 
             (find-file file-name)
 
             (rename-buffer (wg-buf-name buf) t)
 
             (wg-set-buffer-uid-or-error (wg-buf-uid buf))
 
             (when wg-restore-mark
 
               (set-mark (wg-buf-mark buf))
 
               (deactivate-mark))
 
             (wg-deserialize-buffer-local-variables buf)
 
             (current-buffer))
 
            (t
 
             ;; try directory
 
             (if (not (file-remote-p file-name))
 
                 (if (file-directory-p (file-name-directory file-name))
 
                     (progn
 
                       (dired (file-name-directory file-name))
 
                       (current-buffer))
 
                   (progn
 
                     (message "Attempt to restore nonexistent file: %S" file-name)
 
                     nil))
 
               nil)
 
             )))))
 

	
 
(defun wg-restore-special-buffer (buf)
 
  "Restore a buffer BUF with DESERIALIZER-FN."
 
  (wg-when-let
 
      ((special-data (wg-buf-special-data buf))
 
       (buffer (save-window-excursion
 
                 (condition-case err
 
                     (funcall (car special-data) buf)
 
                   (error (message "Error deserializing %S: %S"
 
                                   (wg-buf-name buf) err)
 
                          nil)))))
 
    (switch-to-buffer buffer t)
 
    (wg-set-buffer-uid-or-error (wg-buf-uid buf))
 
    buffer))
 

	
 
(defun wg-restore-buffer (buf)
 
  "Restore BUF and return it."
 
  (let (wg-buffer-auto-association-on)
 
    (or (wg-restore-existing-buffer buf)
 
        (wg-restore-special-buffer buf)
 
        (wg-restore-file-buffer buf)
 
        (progn (wg-restore-default-buffer) nil))))
 

	
 
(defun wg-restore-window-positions (win &optional window)
 
  "Restore various positions in WINDOW from their values in WIN."
 
  (let ((window (or window (selected-window))))
 
    (wg-with-slots win
 
        ((win-point wg-win-point)
 
         (win-start wg-win-start)
 
         (win-hscroll wg-win-hscroll))
 
      (set-window-start window win-start t)
 
      (set-window-hscroll window win-hscroll)
 
      (set-window-point
 
       window
 
       (cond ((not wg-restore-point) win-start)
 
             ((eq win-point :max) (point-max))
 
             (t win-point)))
 
      (when (>= win-start (point-max)) (recenter)))))
 

	
 
(defun wg-restore-window (win)
 
  "Restore WIN in `selected-window'."
 
  (let ((selwin (selected-window))
 
        (buf (wg-find-buf-by-uid (wg-win-buf-uid win))))
 
    (if (not buf) (wg-restore-default-buffer)
 
      (when (wg-restore-buffer buf)
 
        (wg-restore-window-positions win selwin)
 
        (when wg-restore-window-dedicated-p
 
          (set-window-dedicated-p selwin (wg-win-dedicated win)))))))
 

	
 
(defun wg-reset-window-tree ()
 
  "Delete all but one window in `selected-frame', and reset
 
various parameters of that window in preparation for restoring
 
a wtree."
 
  (delete-other-windows)
 
  (set-window-dedicated-p nil nil))
 

	
 
(defun wg-restore-window-tree-helper (w)
 
  "Recursion helper for `wg-restore-window-tree'."
 
  (if (wg-wtree-p w)
 
      (cl-loop with dir = (wg-wtree-dir w)
 
               for (win . rest) on (wg-wtree-wlist w)
 
               do (when rest (split-window nil (wg-w-size win dir) (not dir)))
 
               do (wg-restore-window-tree-helper win))
 
    (wg-restore-window w)
 
    (when (wg-win-selected w)
 
      (setq wg-window-tree-selected-window (selected-window)))
 
    (when (wg-win-minibuffer-scroll w)
 
      (setq minibuffer-scroll-window (selected-window)))
 
    (other-window 1)))
 

	
 
(defun wg-restore-window-tree (wtree)
 
  "Restore WTREE in `selected-frame'."
 
  (let ((window-min-width wg-window-min-width)
 
        (window-min-height wg-window-min-height)
 
        (wg-window-tree-selected-window nil))
 
    (wg-reset-window-tree)
 
    (wg-restore-window-tree-helper wtree)
 
    (wg-awhen wg-window-tree-selected-window (select-window it))))
 

	
 
(defun wg-wconfig-restore-frame-position (wconfig)
 
  "Restore `selected-frame's position from WCONFIG."
 
(defun wg-wconfig-restore-frame-position (wconfig &optional frame)
 
  "Use WCONFIG to restore FRAME's position.
 
If frame is nil then `selected-frame'."
 
  (wg-when-let ((left (wg-wconfig-left wconfig))
 
                (top (wg-wconfig-top wconfig)))
 
    ;; Check that arguments are integers
 
    ;; Problem: https://github.com/pashinin/workgroups2/issues/15
 
    (if (and (integerp left)
 
             (integerp top))
 
        (set-frame-position (selected-frame) left top))))
 
        (set-frame-position frame left top))))
 

	
 
(defun wg-wconfig-restore-scroll-bars (wconfig)
 
  "Restore `selected-frame's scroll-bar settings from WCONFIG."
 
  (set-frame-parameter
 
   nil 'vertical-scroll-bars (wg-wconfig-vertical-scroll-bars wconfig))
 
  (set-frame-parameter
 
   nil 'scroll-bar-width (wg-wconfig-scroll-bar-width wconfig)))
 

	
 
;;(defun wg-wconfig-restore-fullscreen (wconfig)
 
;;  "Restore `selected-frame's fullscreen settings from WCONFIG."
 
;;  (set-frame-parameter
 
;;   nil 'fullscreen (wg-wconfig-parameters wconfig))
 
;;  )
 

	
 
(defun wg-scale-wconfig-to-frame (wconfig)
 
  "Scale WCONFIG buffers to fit current frame size.
 
Return a scaled copy of WCONFIG."
 
  (interactive)
 
  (wg-scale-wconfigs-wtree wconfig
 
                           (frame-parameter nil 'width)
 
                           (frame-parameter nil 'height)))
 

	
 
(defun wg-frame-resize-and-position (wconfig)
 
  "Resize and position a frame based on WCONFIG of current workgroup."
 
(defun wg-frame-resize-and-position (wconfig &optional frame)
 
  "Apply WCONFIG's size and position to a FRAME."
 
  (interactive)
 
  (unless frame
 
    (setq frame (selected-frame)))
 
  (let* ((params (wg-wconfig-parameters wconfig))
 
         fullscreen)
 
    (set-frame-parameter nil 'fullscreen (if (assoc 'fullscreen params)
 
                                             (cdr (assoc 'fullscreen params))
 
                                           nil))
 
    (set-frame-parameter frame 'fullscreen (if (assoc 'fullscreen params)
 
                                               (cdr (assoc 'fullscreen params))
 
                                             nil))
 
    (when (and wg-restore-frame-position
 
               (not (frame-parameter nil 'fullscreen)))
 
      (wg-wconfig-restore-frame-position wconfig))
 
               (not (frame-parameter frame 'fullscreen)))
 
      (wg-wconfig-restore-frame-position wconfig frame))
 
    ))
 

	
 
(defun wg-restore-frame-size-position (wconfig)
 
(defun wg-restore-frame-size-position (wconfig &optional fs)
 
  "Smart-restore of frame size and position.
 

	
 
Depending on `wg-remember-frame-for-each-wg' frame parameters may
 
be restored for each workgroup.
 

	
 
If `wg-remember-frame-for-each-wg' is nil (by default) then
 
current frame parameters are saved/restored to/from first
 
workgroup. And frame parameters for all other workgroups are just
 
ignored.
 
"
 
  (interactive)
 
  (let* ((params (wg-wconfig-parameters wconfig))
 
         fullscreen)
 
    ;; Frame maximized / fullscreen / none
 
    (unless wg-remember-frame-for-each-wg
 
      (setq params (wg-wconfig-parameters (wg-workgroup-working-wconfig (wg-first-workgroup)))))
 
    (setq fullscreen (if (assoc 'fullscreen params)
 
                         (cdr (assoc 'fullscreen params))
 
                       nil))
 
    (when (and fullscreen
 
             (or wg-remember-frame-for-each-wg
 
                 (null (wg-current-workgroup t))))
 
    (when (and fs
 
               fullscreen
 
               (or wg-remember-frame-for-each-wg
 
                   (null (wg-current-workgroup t))))
 
      (set-frame-parameter nil 'fullscreen fullscreen)
 
      ;; I had bugs restoring maximized frame:
 
      ;; Frame could be maximized but buffers are not scaled to fit it.
 
      ;;
 
      ;; Maybe because of `set-frame-parameter' takes some time to finish and is async.
 
      ;; So I tried this and it helped
 
      (sleep-for 0 100))
 

	
 
    ;; Position
 
    (when (and wg-restore-frame-position
 
               wg-remember-frame-for-each-wg
 
               (not (frame-parameter nil 'fullscreen)))
 
      (wg-wconfig-restore-frame-position wconfig))
 
    ))
 

	
 
;; FIXME: throw a specific error if the restoration was unsuccessful
 
(defun wg-restore-wconfig (wconfig)
 
  "Restore a workgroup configuration WCONFIG in `selected-frame'.
 
(defun wg-restore-frames ()
 
  "Try to recreate opened frames, take info from session's 'frame-list parameter."
 
  (interactive)
 
  (delete-other-frames)
 
  (when (wg-current-session t)
 
    (let ((fl (wg-session-parameter (wg-current-session t) 'frame-list nil))
 
          (frame (selected-frame)))
 
      (mapc (lambda (wconfig)
 
              (with-selected-frame (make-frame)
 
                ;;(wg-frame-resize-and-position wconfig)
 
                ;;(wg-restore-frame-size-position wconfig)
 
                ;;(wg-wconfig-restore-frame-position wconfig)
 
                (wg-restore-wconfig wconfig)
 
                )) fl)
 
      (select-frame-set-input-focus frame))))
 

	
 
;; FIXME: throw a specific error if the restoration was unsuccessful
 
(defun wg-restore-wconfig (wconfig &optional frame)
 
  "Restore a workgroup configuration WCONFIG in a FRAME.
 
Runs each time you're switching workgroups."
 
  (unless frame
 
    (setq frame (selected-frame)))
 
  (let ((wg-record-incorrectly-restored-bufs t)
 
        (wg-incorrectly-restored-bufs nil)
 
        (params (wg-wconfig-parameters wconfig))
 
        fullscreen wtree)
 
    (wg-barf-on-active-minibuffer)
 
    (wg-restore-frame-size-position wconfig)
 
    (when wg-restore-scroll-bars
 
      (wg-wconfig-restore-scroll-bars wconfig))
 
    (setq wtree (wg-scale-wconfig-to-frame wconfig))  ; scale wtree to frame size
 

	
 
    ;; Restore buffers
 
    (wg-restore-window-tree wtree)
 

	
 
    ;; Restore frame position
 
    (when (and wg-restore-frame-position
 
               (not (frame-parameter nil 'fullscreen))
 
               (null (wg-current-workgroup t)))
 
      (wg-wconfig-restore-frame-position wconfig))
 
      (wg-wconfig-restore-frame-position wconfig frame))
 

	
 
    (when wg-incorrectly-restored-bufs
 
      (message "Unable to restore these buffers: %S\
 
If you want, restore them manually and try again."
 
               (mapcar 'wg-buf-name wg-incorrectly-restored-bufs)))))
 

	
 

	
 

	
 
(provide 'workgroups-restore)
 
;;; workgroups-restore.el ends here
src/workgroups-structs.el
Show inline comments
 
;;; workgroups-structs.el --- Data structures for WG
 
;;; Commentary:
 
;;
 
;; Copyright (C) Sergey Pashinin
 
;; Author: Sergey Pashinin <sergey@pashinin.com>
 
;;
 
;; `wg-defstruct'
 
;;
 
;; It creates some functions named like "wg-buf-...", "wg-session-..."
 
;;
 
;; To get a value you can use:
 
;; (wg-session-... (wg-current-session))
 
;; Like:
 
;; (wg-session-file-name (wg-current-session))
 
;; (wg-workgroup-parameters (wg-current-workgroup))
 
;;
 
;; To set a value (in `wg-write-session-file'):
 
;;
 
;; (setf (wg-session-file-name (wg-current-session)) filename)
 
;;
 
;;; Code:
 

	
 
(require 'workgroups-utils-basic)
 

	
 
(wg-defstruct wg buf
 
  (uid (wg-generate-uid))
 
  (name)
 
  (file-name)
 
  (point)
 
  (mark)
 
  (local-vars)
 
  (special-data)
 
  ;; This may be used later:
 
  (gc))
 

	
 
(wg-defstruct wg win
 
  (uid)
 
  (parameters)
 
  (edges)
 
  (point)
 
  (start)
 
  (hscroll)
 
  (dedicated)
 
  (selected)
 
  (minibuffer-scroll)
 
  (buf-uid))
 

	
 
(wg-defstruct wg wtree
 
  (uid)
 
  (dir)
 
  (edges)
 
  (wlist))
 

	
 
(wg-defstruct wg wconfig
 
  (uid (wg-generate-uid))
 
  (name)
 
  (parameters)
 
  (left)
 
  (top)
 
  (width)
 
  (height)
 
  (vertical-scroll-bars)
 
  (scroll-bar-width)
 
  (wtree)
 
  ;;(fullscreen)
 
  )
 
;; wg-wconfig
 
  (wtree))
 

	
 
(wg-defstruct wg workgroup
 
  (uid (wg-generate-uid))
 
  (name)
 
  (modified)
 
  (parameters)
 
  (base-wconfig)
 
  (selected-frame-wconfig)
 
  (saved-wconfigs)
 
  (strong-buf-uids)
 
  (weak-buf-uids))
 

	
 
(wg-defstruct wg session
 
  (uid (wg-generate-uid))
 
  (name)
 
  (modified)
 
  (parameters)
 
  (file-name)
 
  (version wg-version)
 
  (workgroup-list)
 
  (buf-list))
 

	
 
(wg-defstruct wg workgroup-state
 
  (undo-pointer)
 
  (undo-list))
 

	
 
(provide 'workgroups-structs)
 
;;; workgroups-structs.el ends here
src/workgroups-variables.el
Show inline comments
 
;;; workgroups-variables --- Workgroups vars and consts
 
;;; Commentary:
 
;;; Code:
 

	
 
(defconst wg-version "1.0.3"
 
  "Current version of workgroups.")
 

	
 
;;; customization
 

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

	
 
(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-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)
 

	
 

	
 
;; keybinding customization
 

	
 
(defcustom wg-prefix-key (kbd "C-c z")
 
  "Workgroups' prefix key.
 
Setting this variable requires that `workgroups-mode' be turned
 
off and then on again to take effect."
 
  :type 'string
 
  :group 'workgroups)
 

	
 

	
 
;; 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-buffer-list-finalization-hook nil
 
  "Functions in this hook can modify `wg-temp-buffer-list'
 
arbitrarily, provided its final value is still a list of the
 
names of live buffer.  Any final adjustments the user wishes to
 
make to the filtered buffer list before ido/iswitchb get ahold of
 
it should be made here."
 
  :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)
 

	
 

	
 
;; save and load customization
 
(defcustom wg-use-default-session-file (not (daemonp))
 
  "Generally, non-nil means take care of saving and loading automatically,
 
and nil means leave it up to the user.
 

	
 
FIXME: docstring this"
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-default-session-file
 
  "~/.emacs_workgroups"
 
  "Default filename to be used to save workgroups."
 
  :type 'file
 
  :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)
 

	
 
(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)
 

	
 

	
 
;; minibuffer customization
 

	
 
(defcustom wg-confirm-on-get-workgroup-create nil
 
  "Non-nil means request confirmation before creating a new
 
workgroup when `wg-get-workgroup-create' is called with a string
 
that doesn't name an existing workgroup."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-no-confirm-on-destructive-operation nil
 
  "Non-nil means don't request confirmation before various
 
destructive operations, like `wg-reset'."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-minibuffer-message-timeout 0.75
 
  "Bound to `minibuffer-message-timeout' when messaging while the
 
minibuffer is active."
 
  :type 'float
 
  :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-special-buffer-serdes-functions
 
  '(wg-serialize-comint-buffer
 
    wg-serialize-speedbar-buffer)
 
  "List of functions providing special buffer serialization/deserialization.
 

	
 
Use `wg-support' macro and this variable will be filled
 
automatically.
 

	
 
An entry should be either a function symbol or a lambda, and should
 
accept a single Emacs buffer object as an argument.
 

	
 
When a buffer is to be serialized, it is passed to each of these
 
functions in turn until one returns non-nil, or the list ends.  A
 
return value of nil indicates that the function can't handle
 
buffers of that type.  A non-nil return value indicates that it
 
can.  The first non-nil return value becomes the buffer's special
 
serialization data.  The return value should be a cons, with a
 
deserialization function (a function symbol or a lambda) as the car,
 
and any other serialization data as the cdr.
 

	
 
When it comes time to deserialize the buffer, the deserialization
 
function (the car of the cons mentioned above) is passed the
 
wg-buf object, from which it should restore the buffer.  The
 
special serialization data itself can be accessed
 
with (cdr (wg-buf-special-data <wg-buf>)).  The deserialization
 
function must return the restored Emacs buffer object.
 

	
 
See the definitions of the functions in this list for examples of
 
how to write your own."
 
  :type 'alist
 
  :group 'workgroups)
 

	
 
(defcustom wg-default-buffer "*scratch*"
 
  "Buffer made visible a window when the window's actual buffer
 
can't be restored.  Also used when a blank workgroup is created."
 
  :type 'string
 
  :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-associated-buffers nil
 
  "Non-nil means restore ALL buffers associated (opened in) with
 
the workgroup on workgroup restore.  \"nil\" means to restore
 
only needed buffers to show them to you."
 
  :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)
 

	
 

	
 
;; wconfig undo/redo customization
 

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

	
 

	
 
;; wconfig kill-ring customization
 

	
 
(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)
 
    (associated "associated" wg-buffer-list-filter-associated)
 
    (unassociated "unassociated" wg-buffer-list-filter-unassociated)
 
    (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
 

	
 
`associated'    Only the names of those live buffers that have
 
                been associated with the current workgroup
 

	
 
`unassociated'  Only the names of those live buffers that are
 
                unassociated with the current workgroup
 

	
 
`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.
 

	
 
A few example custom buffer-list filtration functions are
 
included, like `wg-buffer-list-filter-home-dir',
 
`wg-buffer-list-filter-irc' and `wg-buffer-list-filter-elisp'.
 
See their definitions for more info on how they're defined, and
 
the utilities they're built on.
 

	
 
Here's an example of how to add an `elisp' buffer-list-filter
 
definition to `wg-buffer-list-filter-definitions' using the
 
example function `wg-buffer-list-filter-elisp':
 

	
 
(add-to-list
 
 'wg-buffer-list-filter-definitions
 
 '(elisp \"elisp\" wg-buffer-list-filter-elisp))
 

	
 
After this form has been evaluated, `elisp' can be used wherever
 
other buffer-list-filter identifiers are used, like in
 
`wg-buffer-list-filter-order-alist'.
 

	
 
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 associated unassociated 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
 
`switch-to-buffer', `switch-to-buffer-other-window',
 
`switch-to-buffer-other-frame', `kill-buffer', `next-buffer',
 
`previous-buffer', `display-buffer', `insert-buffer',
 
`read-buffer', or the special symbol `default', which defines the
 
buffer-list-filter order for all commands not present in this
 
alist.
 

	
 
The cdr of each entry should be a list of buffer-list-filter
 
identifiers defining the order in which filtered buffer-lists are
 
presented for the command.  See
 
`wg-buffer-list-filter-definitions'.
 

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

	
 
(defcustom wg-center-rotate-buffer-list-display nil
 
  "Non-nil means rotate the buffer list display so that the
 
current buffer is in the center of the list.  This can make it
 
easier to see the where `wg-previous-buffer' will take you, but
 
it doesn't look right if the buffer list display is long enough
 
to wrap in the miniwindow."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-buffer-auto-association-on t
 
  "Non-nil means buffer auto-association is on.
 
nil means it's off.  See `wg-buffer-auto-association'."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-buffer-auto-association 'weak
 
  "Specifies the behavior for auto-associating buffers with workgroups.
 

	
 
When a buffer is made visible in a window it can be automatically
 
associated with the current workgroup in the window's frame.
 
This setting determines whether and how that happens.
 

	
 
Allowable values:
 

	
 
`weak' - weakly associate the buffer with the workgroup
 

	
 
`strong' - strongly associate the buffer with the workgroup
 

	
 
A function (a function-symbol or a lambda) - `funcall' the function to
 
determine whether and how to associate the buffer with the
 
workgroup.  The function should accept two arguments -- the
 
buffer and the workgroup -- and should return one of the
 
allowable values for this variable.
 

	
 
`nil' or any other value - don't associate the buffer with the
 
workgroup.
 

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

	
 
(defcustom wg-dissociate-buffer-on-kill-buffer t
 
  "Non-nil means dissociate from the current workgroup buffers
 
killed with `kill-buffer'."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-remap-switch-to-buffer nil
 
  "Non-nil means remap `switch-to-buffer' to `wg-switch-to-buffer'."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-remap-switch-to-buffer-other-window nil
 
  "Non-nil means remap `switch-to-buffer-other-window' to
 
`wg-switch-to-buffer-other-window'.  Otherwise, don't remap."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-remap-switch-to-buffer-other-frame nil
 
  "Non-nil means remap `switch-to-buffer-other-frame' to
 
`wg-switch-to-buffer-other-frame'.  Otherwise, don't remap."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-remap-kill-buffer nil
 
  "Non-nil means remap `kill-buffer' to `wg-kill-buffer'.
 
Otherwise, don't remap."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-remap-display-buffer nil
 
  "Non-nil means remap `display-buffer' to `wg-display-buffer'.
 
Otherwise, don't remap."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-remap-insert-buffer nil
 
  "Non-nil means remap `insert-buffer' to `wg-insert-buffer'.
 
Otherwise, don't remap."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-remap-next-buffer nil
 
  "Non-nil means remap `next-buffer' to `wg-next-buffer'.
 
Otherwise, don't remap."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-remap-previous-buffer nil
 
  "Non-nil means remap `previous-buffer' to `wg-previous-buffer'.
 
Otherwise, don't remap."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-remap-bury-buffer 'bury
 
  "Non-nil means remap `bury-buffer'.
 
`banish' means remap `bury-buffer' to `wg-banish-buffer'.
 
`bury' or other non-nil means remap `bury-buffer' to
 
`wg-bury-buffer'.  Otherwise, don't remap."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-ido-entry-buffer-replacement-regexp "^ .*Minibuf.*$"
 
  "Regexp matching the name of a buffer to replace `ido-entry-buffer'.
 
The regexp should match the name of a live buffer that will never
 
be a completion candidate under normal circumstances.  You
 
probably don't want to change this.  See
 
`wg-get-sneaky-ido-entry-buffer-replacement'."
 
  :type 'regexp
 
  :group 'workgroups)
 

	
 

	
 
;; mode-line customization
 

	
 
(defcustom wg-mode-line-display-on t
 
  "Toggles Workgroups' mode-line display."
 
  :type 'boolean
 
  :group 'workgroups
 
  :set (lambda (sym val)
 
         (custom-set-default sym val)
 
         (force-mode-line-update)))
 

	
 
(defcustom wg-mode-line-use-faces nil
 
  "Non-nil means use faces in the mode-line display.
 
It can be tricky to choose faces that are visible in both active
 
and inactive mode-lines, so this feature defaults to off."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-mode-line-disable (featurep 'powerline)
 
  "Do not do any modeline modifications."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-mode-line-only-name t
 
  "Display only workgroup name in modeline without any flags."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-mode-line-decor-left-brace "("
 
  "String displayed at the left of the mode-line display."
 
  :type 'string
 
  :group 'workgroups)
 

	
 
(defcustom wg-mode-line-decor-right-brace ")"
 
  "String displayed at the right of the mode-line display."
 
  :type 'string
 
  :group 'workgroups)
 

	
 
(defcustom wg-mode-line-decor-divider ":"
 
  "String displayed between elements of the mode-line display."
 
  :type 'string
 
  :group 'workgroups)
 

	
 
(defcustom wg-mode-line-decor-strongly-associated
 
  #("@" 0 1 (help-echo "This buffer is strongly associated with the \
 
current workgroup"))
 
  "Indicates that a buffer is strongly associated with the current workgroup."
 
  :type 'string
 
  :group 'workgroups)
 

	
 
(defcustom wg-mode-line-decor-weakly-associated
 
  #("~" 0 1 (help-echo "This buffer is weakly associated with the \
 
current workgroup"))
 
  "Indicates that a buffer is weakly associated with the current workgroup."
 
  :type 'string
 
  :group 'workgroups)
 

	
 
(defcustom wg-mode-line-decor-unassociated
 
  #("-" 0 1 (help-echo "This buffer is unassociated with the \
 
current workgroup"))
 
  "Indicates that a buffer is unassociated with the current workgroup."
 
  :type 'string
 
  :group 'workgroups)
 

	
 
(defcustom wg-mode-line-decor-window-dedicated
 
  #("#" 0 1 (help-echo "This window is dedicated to its buffer."))
 
  "Indicates that the window is dedicated to its buffer."
 
  :type 'string
 
  :group 'workgroups)
 

	
 
(defcustom wg-mode-line-decor-window-undedicated
 
  #("-" 0 1 (help-echo "This window is not dedicated to its buffer."))
 
  "Indicates that the window is not dedicated to its buffer."
 
  :type 'string
 
  :group 'workgroups)
 

	
 
(defcustom wg-mode-line-decor-session-modified
 
  #("*" 0 1 (help-echo "The session is modified"))
 
  "Indicates that the session is modified."
 
  :type 'string
 
  :group 'workgroups)
 

	
 
(defcustom wg-mode-line-decor-session-unmodified
 
  #("-" 0 1 (help-echo "The session is unmodified"))
 
  "Indicates that the session is unmodified."
 
  :type 'string
 
  :group 'workgroups)
 

	
 
(defcustom wg-mode-line-decor-workgroup-modified
 
  #("*" 0 1 (help-echo "The current workgroup is modified"))
 
  "Indicates that the current workgroup is modified."
 
  :type 'string
 
  :group 'workgroups)
 

	
 
(defcustom wg-mode-line-decor-workgroup-unmodified
 
  #("-" 0 1 (help-echo "The current workgroup is unmodified"))
 
  "Indicates that the current workgroup is unmodified."
 
  :type 'string
 
  :group 'workgroups)
 

	
 

	
 
;; display customization
 

	
 
(defcustom wg-use-faces t
 
  "Non-nil means use faces in various displays."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-time-format "%H:%M:%S %A, %B %d %Y"
 
  "Format string for time display.  Passed to `format-time-string'."
 
  :type 'string
 
  :group 'workgroups)
 

	
 
(defcustom wg-display-battery t
 
  "Non-nil means include `battery', when available, in the time display."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
(defcustom wg-list-display-decor-left-brace "( "
 
  "String displayed to the left of the list display."
 
  :type 'string
 
  :group 'workgroups)
 

	
 
(defcustom wg-list-display-decor-right-brace " )"
 
  "String displayed to the right of the list display."
 
  :type 'string
 
  :group 'workgroups)
 

	
 
(defcustom wg-list-display-decor-divider " | "
 
  "String displayed between elements of the list display."
 
  :type 'string
 
  :group 'workgroups)
 

	
 
(defcustom wg-list-display-decor-current-left "-<{ "
 
  "String displayed to the left of the current element of the list display."
 
  :type 'string
 
  :group 'workgroups)
 

	
 
(defcustom wg-list-display-decor-current-right " }>-"
 
  "String displayed to the right of the current element of the list display."
 
  :type 'string
 
  :group 'workgroups)
 

	
 
(defcustom wg-list-display-decor-previous-left "< "
 
  "String displayed to the left of the previous element of the list display."
 
  :type 'string
 
  :group 'workgroups)
 

	
 
(defcustom wg-list-display-decor-previous-right " >"
 
  "String displayed to the right of the previous element of the list display."
 
  :type 'string
 
  :group 'workgroups)
 

	
 
(defcustom wg-associate-buffers t
 
  "Non-nil means when emacs chooses a buffer to display in a
 
workgroup, prefer buffers whose most recent appearance was in
 
that workgroup."
 
  :type 'boolean
 
  :group 'workgroups)
 

	
 
;;; vars
 

	
 
(defvar workgroups-mode-map nil
 
  "Workgroups Mode's keymap")
 

	
 
(defvar wg-current-session nil
 
  "Current session object.")
 

	
 
(defvar wg-workgroups-mode-minor-mode-map-entry nil
 
  "Workgroups' minor-mode-map entry.")
 

	
 
(defvar wg-wconfig-kill-ring nil
 
  "Ring of killed or kill-ring-saved wconfigs.")
 

	
 
(defvar wg-last-message nil
 
  "Holds the last message Workgroups sent to the echo area.")
 

	
 
(defvar wg-face-abbrevs nil
 
  "Assoc list mapping face abbreviations to face names.")
 

	
 
(defvar wg-buffer-uid nil
 
  "Symbol for the current buffer's wg-buf's uid.
 
Every Workgroups buffer object (wg-buf) has a uid.  When
 
Workgroups creates or encounters an Emacs buffer object
 
corresponding to a wg-buf, it tags it with the wg-buf's uid to
 
unambiguously pair the two.")
 
(make-variable-buffer-local 'wg-buffer-uid)
 

	
 

	
 
;; file and modified flag vars
 

	
 
(defvar wg-flag-modified t
 
  "Dynamically bound to nil around destructive operations to
 
temporarily disable flagging `modified'.")
 

	
 

	
 
;; undo vars
 

	
 
(defvar wg-window-configuration-changed nil
 
  "Flag set by `window-configuration-change-hook'.")
 

	
 
(defvar wg-already-updated-working-wconfig nil
 
  "Flag set by `wg-update-working-wconfig-hook'.")
 

	
 
(defvar wg-undoify-window-configuration-change t
 
  "Flag unset when changes to the window config shouldn't cause
 
workgroups' undo info to be updated.")
 

	
 
(defvar wg-just-exited-minibuffer nil
 
  "Flag set by `minibuffer-exit-hook' to exempt from
 
undoification those window-configuration changes caused by
 
exiting the minibuffer.  This is ugly, but necessary.  It may
 
seem like we could just null out
 
`wg-undoify-window-configuration-change' in
 
`minibuffer-exit-hook', but that also prevents undoification of
 
window configuration changes triggered by commands called with
 
`execute-extended-command' -- i.e. it's just too coarse.")
 

	
 

	
 
;; buffer-list-filter vars
 

	
 
(defvar wg-current-workgroup nil
 
  "Bound to the current workgroup in `wg-with-buffer-list-filters'.")
 

	
 
;; (defvar wg-current-buffer-command nil
 
;;   "Bound to the current buffer command in `wg-with-buffer-list-filters'.")
 

	
 
(defvar wg-current-buffer-list-filter-id nil
 
  "Bound to the current buffer-list-filter symbol in `wg-with-buffer-list-filters'.")
 

	
 
(defvar wg-previous-minibuffer-contents nil
 
  "Holds the previous minibuffer contents for re-insertion when
 
the buffer-list-filter is cycled.")
 

	
 
(defvar wg-ido-method-translations
 
  `((switch-to-buffer              . selected-window)
 
    (switch-to-buffer-other-window . other-window)
 
    (switch-to-buffer-other-frame  . other-frame)
 
    (kill-buffer                   . kill)
 
    (insert-buffer                 . insert)
 
    (display-buffer                . display))
 
  "Alist mapping buffer commands to ido buffer methods.")
 

	
 
(defvar wg-iswitchb-method-translations
 
  `((switch-to-buffer              . samewindow)
 
    (switch-to-buffer-other-window . otherwindow)
 
    (switch-to-buffer-other-frame  . otherframe)
 
    (kill-buffer                   . kill)
 
    (insert-buffer                 . insert)
 
    (display-buffer                . display))
 
  "Alist mapping buffer commands to iswitchb buffer methods.")
 

	
 
(defvar wg-buffer-internal-default-buffer nil
 
  "Bound to `wg-buffer-internal's optional DEFAULT argument for
 
use by buffer list filtration hooks.")
 

	
 
(defvar wg-temp-buffer-list nil
 
  "Dynamically bound to the filtered buffer list in
 
`wg-finalize-buffer-list'.  Functions in
 
`wg-buffer-list-finalization-hook' should modify this variable.")
 

	
 

	
 
;; wconfig restoration
 

	
 
(defvar wg-window-min-width 2
 
  "Bound to `window-min-width' when restoring wtrees. ")
 

	
 
(defvar wg-window-min-height 1
 
  "Bound to `window-min-height' when restoring wtrees.")
 

	
 
(defvar wg-window-min-pad 2
 
  "Added to `wg-window-min-foo' to produce the actual minimum window size.")
 

	
 
(defvar wg-actual-min-width (+ wg-window-min-width wg-window-min-pad)
 
  "Actual minimum window width when creating windows.")
 

	
 
(defvar wg-actual-min-height (+ wg-window-min-height wg-window-min-pad)
 
  "Actual minimum window height when creating windows.")
 

	
 
(defvar wg-min-edges `(0 0 ,wg-actual-min-width ,wg-actual-min-height)
 
  "Smallest allowable edge list of windows created by Workgroups.")
 

	
 
(defvar wg-null-edges '(0 0 0 0)
 
  "Null edge list.")
 

	
 
(defvar wg-window-tree-selected-window nil
 
  "Used during wconfig restoration to hold the selected window.")
 

	
 
(defvar wg-update-current-workgroup-working-wconfig-on-select-frame t
 
  "Non-nil means update `selected-frame's current workgroup's
 
working wconfig before `select-frame' selects a new frame.
 
let-bind this to nil around forms in which you don't want this to
 
happen.")
 

	
 

	
 
(defvar wg-buffer-workgroup nil
 
  "Buffer-local variable associating each buffer with the
 
  workgroup in which it most recently appeared.")
 
(make-variable-buffer-local 'wg-buffer-workgroup)
 

	
 
(defvar wg-deactivation-list nil
 
  "A stack of workgroups that are currently being switched away from.
 
Used to avoid associating the old workgroup's buffers with the
 
new workgroup during a switch.")
 

	
 
(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.")
 

	
 
;;; faces
 

	
 
(defmacro wg-defface (face key spec doc &rest args)
 
  "`defface' wrapper adding a lookup key used by `wg-fontify'."
 
  (declare (indent 2))
 
  `(progn
 
     (cl-pushnew (cons ,key ',face) wg-face-abbrevs :test #'equal)
 
     (defface ,face ,spec ,doc ,@args)))
 

	
 
(wg-defface wg-current-workgroup-face :cur
 
  '((t :inherit font-lock-constant-face :bold nil))
 
  "Face used for current elements in list displays."
 
  :group 'workgroups)
 

	
 
(wg-defface wg-previous-workgroup-face :prev
 
  '((t :inherit font-lock-keyword-face :bold nil))
 
  "Face used for the name of the previous workgroup in the list display."
 
  :group 'workgroups)
 

	
 
(wg-defface wg-other-workgroup-face :other
 
  '((t :inherit font-lock-string-face :bold nil))
 
  "Face used for the names of other workgroups in the list display."
 
  :group 'workgroups)
 

	
 
(wg-defface wg-command-face :cmd
 
  '((t :inherit font-lock-function-name-face :bold nil))
 
  "Face used for command/operation strings."
 
  :group 'workgroups)
 

	
 
(wg-defface wg-divider-face :div
 
  '((t :inherit font-lock-builtin-face :bold nil))
 
  "Face used for dividers."
 
  :group 'workgroups)
 

	
 
(wg-defface wg-brace-face :brace
 
  '((t :inherit font-lock-builtin-face :bold nil))
 
  "Face used for left and right braces."
 
  :group 'workgroups)
 

	
 
(wg-defface wg-message-face :msg
 
  '((t :inherit font-lock-string-face :bold nil))
 
  "Face used for messages."
 
  :group 'workgroups)
 

	
 
(wg-defface wg-mode-line-face :mode
 
  '((t :inherit font-lock-doc-face :bold nil))
 
  "Face used for workgroup position and name in the mode-line display."
 
  :group 'workgroups)
 

	
 
(wg-defface wg-filename-face :file
 
  '((t :inherit font-lock-keyword-face :bold nil))
 
  "Face used for filenames."
 
  :group 'workgroups)
 

	
 
(provide 'workgroups-variables)
 
;;; workgroups-variables.el ends here
0 comments (0 inline, 0 general)