Changeset - d49e33f7e3f1
[Not reviewed]
0 1 0
Sergey Pashinin - 11 years ago 2014-08-25 13:34:50
sergey@pashinin.com
minor changes
1 file changed with 12 insertions and 14 deletions:
0 comments (0 inline, 0 general)
src/workgroups2.el
Show inline comments
 
@@ -2042,216 +2042,214 @@ Return value."
 
    (wg-win (wg-copy-win w))
 
    (wg-wtree (wg-copy-wtree w))))
 

	
 
(defun wg-set-edges (w edges)
 
  "Set W's EDGES list, and return W."
 
  (cl-etypecase w
 
    (wg-win (setf (wg-win-edges w) edges))
 
    (wg-wtree (setf (wg-wtree-edges w) edges)))
 
  w)
 

	
 
(defun wg-equal-wtrees (w1 w2)
 
  "Return t when W1 and W2 have equal structure."
 
  (cond ((and (wg-win-p w1) (wg-win-p w2))
 
         (equal (wg-w-edges w1) (wg-w-edges w2)))
 
        ((and (wg-wtree-p w1) (wg-wtree-p w2))
 
         (and (eq (wg-wtree-dir w1) (wg-wtree-dir w2))
 
              (equal (wg-wtree-edges w1) (wg-wtree-edges w2))
 
              (cl-every #'wg-equal-wtrees
 
                        (wg-wtree-wlist w1)
 
                        (wg-wtree-wlist w2))))))
 

	
 
(defun wg-normalize-wtree (wtree)
 
  "Clean up and return a new wtree from WTREE.
 
Recalculate the edge lists of all subwins, and remove subwins
 
outside of WTREE's bounds.  If there's only one element in the
 
new wlist, return it instead of a new wtree."
 
  (if (wg-win-p wtree) wtree
 
    (wg-with-slots wtree ((dir wg-wtree-dir)
 
                          (wlist wg-wtree-wlist))
 
      (wg-with-bounds wtree dir (ls1 hs1 lb1 hb1)
 
        (let* ((min-size (wg-min-size dir))
 
               (max (- hb1 1 min-size))
 
               (lastw (-last-item wlist)))
 
          (cl-labels
 
              ((mapwl
 
                (wl)
 
                (wg-dbind (sw . rest) wl
 
                  (cons (wg-normalize-wtree
 
                         (wg-set-bounds
 
                          sw dir ls1 hs1 lb1
 
                          (setq lb1 (if (eq sw lastw) hb1
 
                                      (let ((hb2 (+ lb1 (wg-w-size sw dir))))
 
                                        (if (>= hb2 max) hb1 hb2))))))
 
                        (when (< lb1 max) (mapwl rest))))))
 
            (let ((new (mapwl wlist)))
 
              (if (not (cdr new)) (car new)
 
                (setf (wg-wtree-wlist wtree) new)
 
                wtree))))))))
 

	
 
(defun wg-scale-wtree (wtree wscale hscale)
 
  "Return a copy of WTREE with its dimensions scaled by WSCALE and HSCALE.
 
All WTREE's subwins are scaled as well."
 
  (let ((scaled (wg-scale-w-size wtree wscale hscale)))
 
    (if (wg-win-p wtree) scaled
 
      (wg-asetf (wg-wtree-wlist scaled)
 
                (wg-docar (sw it) (wg-scale-wtree sw wscale hscale)))
 
      scaled)))
 

	
 

	
 
(defun wg-resize-frame-scale-wtree (wconfig)
 
  "Set FRAME's size to WCONFIG's, returning a possibly scaled wtree.
 
If the frame size was set correctly, return WCONFIG's wtree
 
unchanged.  If it wasn't, return a copy of WCONFIG's wtree scaled
 
with `wg-scale-wconfigs-wtree' to fit the frame as it exists."
 
  (let ((frame (selected-frame)))
 
    (wg-with-slots wconfig ((wcwidth wg-wconfig-width)
 
                            (wcheight wg-wconfig-height))
 
      (when window-system (set-frame-size frame wcwidth wcheight))
 
      (let ((fwidth  (frame-parameter frame 'width))
 
            (fheight (frame-parameter frame 'height)))
 
        (if (and (= wcwidth fwidth) (= wcheight fheight))
 
            (wg-wconfig-wtree wconfig)
 
          (wg-scale-wconfigs-wtree wconfig fwidth fheight))))))
 

	
 

	
 
(defun wg-wtree-buf-uids (wtree)
 
  "Return a new list of the buf uids of all wins in WTREE."
 
  (if (not wtree)
 
      (error "WTREE is nil in `wg-wtree-buf-uids'!"))
 
  (wg-flatten-wtree wtree 'wg-win-buf-uid))
 

	
 
(defun wg-wtree-unique-buf-uids (wtree)
 
  "Return a list of the unique buf uids of all wins in WTREE."
 
  (cl-remove-duplicates (wg-wtree-buf-uids wtree) :test 'string=))
 

	
 

	
 

	
 

	
 
(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'."
 
  "Recursion helper for `wg-restore-window-tree' W."
 
  (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)
 
    (awhen wg-window-tree-selected-window (select-window it))))
 

	
 

	
 
;; (wg-window-tree-to-wtree (window-tree))
 
(defun wg-window-tree-to-wtree (window-tree)
 
  "Return the serialization (a wg-wtree) of Emacs window tree WINDOW-TREE."
 
  (wg-barf-on-active-minibuffer)
 
  (cl-labels
 
      ((inner (w) (if (windowp w) (wg-window-to-win w)
 
                    (wg-dbind (dir edges . wins) w
 
                      (wg-make-wtree
 
                       :dir    dir
 
                       :edges  edges
 
                       :wlist  (mapcar #'inner wins))))))
 
    (let ((w (car window-tree)))
 
      (when (and (windowp w) (window-minibuffer-p w))
 
        (error "Workgroups can't operate on minibuffer-only frames."))
 
      (inner w))))
 

	
 

	
 
(defun wg-flatten-wtree (wtree &optional key)
 
  "Return a new list by flattening WTREE.
 
KEY non returns returns a list of WTREE's wins.
 
KEY non-nil returns a list of the results of calling KEY on each win."
 
  (cl-labels
 
      ((inner (w) (if (wg-win-p w) (list (if key (funcall key w) w))
 
                    (cl-mapcan #'inner (wg-wtree-wlist w)))))
 
    (inner wtree)))
 

	
 
(defun wg-reverse-wlist (w &optional dir)
 
  "Reverse W's wlist and those of all its sub-wtrees in direction DIR.
 
If DIR is nil, reverse WTREE horizontally.
 
If DIR is 'both, reverse WTREE both horizontally and vertically.
 
Otherwise, reverse WTREE vertically."
 
  (cl-labels
 
      ((inner (w) (if (wg-win-p w) w
 
                    (wg-with-slots w ((d1 wg-wtree-dir))
 
                      (wg-make-wtree
 
                       :dir d1
 
                       :edges (wg-wtree-edges w)
 
                       :wlist (let ((wl2 (mapcar #'inner (wg-wtree-wlist w))))
 
                                (if (or (eq dir 'both) (eq dir d1))
 
                                    (nreverse wl2)
 
                                  wl2)))))))
 
    (wg-normalize-wtree (inner w))))
 

	
 
(defun wg-wtree-move-window (wtree offset)
 
  "Offset `selected-window' OFFSET places in WTREE."
 
  (cl-labels
 
      ((inner (w) (if (wg-win-p w) w
 
                    (wg-with-slots w ((wlist wg-wtree-wlist))
 
                      (wg-make-wtree
 
                       :dir (wg-wtree-dir w)
 
                       :edges (wg-wtree-edges w)
 
                       :wlist (aif (cl-find t wlist :key 'wg-win-selected)
 
                                  (wg-cyclic-offset-elt it wlist offset)
 
                                (mapcar #'inner wlist)))))))
 
    (wg-normalize-wtree (inner wtree))))
 

	
 
(defun wg-frame-to-wconfig (&optional frame)
 
  "Return the serialization (a wg-wconfig) of Emacs frame FRAME.
 
FRAME nil defaults to `selected-frame'."
 
  (let* ((frame (or frame (selected-frame)))
 
         (fullscrn (frame-parameter frame 'fullscreen)))
 
    (wg-make-wconfig
 
     :left                  (frame-parameter frame 'left)
 
     :top                   (frame-parameter frame 'top)
 
     :width                 (frame-parameter frame 'width)
 
     :height                (frame-parameter frame 'height)
 
     :parameters            `((fullscreen . ,fullscrn))
 
     :vertical-scroll-bars  (frame-parameter frame 'vertical-scroll-bars)
 
     :scroll-bar-width      (frame-parameter frame 'scroll-bar-width)
 
     :wtree                 (wg-window-tree-to-wtree (window-tree frame))
 
     )))
 

	
 
(defun wg-current-wconfig ()
 
  "Return the current wconfig.
 
If `wg-current-wconfig' is non-nil, return it.  Otherwise return
 
`wg-frame-to-wconfig'."
 
  (or (frame-parameter nil 'wg-current-wconfig)
 
      (wg-frame-to-wconfig)))
 

	
 
(defmacro wg-with-current-wconfig (frame wconfig &rest body)
 
  "Eval BODY with WCONFIG current in FRAME.
 
FRAME nil defaults to `selected-frame'."
 
  (declare (indent 2))
 
  (wg-with-gensyms (frame-sym old-value)
 
    `(let* ((,frame-sym (or ,frame (selected-frame)))
 
            (,old-value (frame-parameter ,frame-sym 'wg-current-wconfig)))
 
       (unwind-protect
 
           (progn
 
             (set-frame-parameter ,frame-sym 'wg-current-wconfig ,wconfig)
 
             ,@body)
 
         (when (frame-live-p ,frame-sym)
 
           (set-frame-parameter ,frame-sym 'wg-current-wconfig ,old-value))))))
 

	
 
(defun wg-make-blank-wconfig (&optional buffer)
 
  "Return a new blank wconfig.
 
BUFFER or `wg-default-buffer' is visible in the only window."
 
  (save-window-excursion
 
@@ -3215,203 +3213,203 @@ If there isn't already a buf corresponding to BUFFER in
 

	
 
(defun wg-bufobj-uid-or-add (bufobj)
 
  "If BUFOBJ is a wg-buf, return its uid.
 
If BUFOBJ is a buffer or a buffer name, see `wg-buffer-uid-or-add'."
 
  (cl-etypecase bufobj
 
    (wg-buf (wg-buf-uid bufobj)) ;; possibly also add to `wg-buf-list'
 
    (buffer (wg-buffer-uid-or-add bufobj))
 
    (string (wg-bufobj-uid-or-add (wg-get-buffer bufobj)))))
 

	
 
(defun wg-reset-buffer (buffer)
 
  "Return BUFFER.
 
Currently only sets BUFFER's `wg-buffer-uid' to nil."
 
  (with-current-buffer buffer (setq wg-buffer-uid nil)))
 

	
 
(defun wg-update-buffer-in-buf-list (&optional buffer)
 
  "Update BUFFER's corresponding buf in `wg-buf-list'.
 
BUFFER nil defaults to `current-buffer'."
 
  (let ((buffer (or buffer (current-buffer))))
 
    (-when-let* ((uid (wg-buffer-uid buffer))
 
                 (old-buf (wg-find-buf-by-uid uid))
 
                 (new-buf (wg-buffer-to-buf buffer)))
 
      (setf (wg-buf-uid new-buf) (wg-buf-uid old-buf))
 
      (wg-asetf (wg-buf-list) (cons new-buf (remove old-buf it))))))
 

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

	
 
(defcustom wg-no-confirm-on-destructive-operation nil
 
  "Do not request confirmation before various destructive operations."
 
  :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)
 

	
 
(defun wg-read-object (prompt test warning &optional initial-contents keymap
 
                              read hist default-value inherit-input-method)
 
  "PROMPT for an object that satisfies TEST.  WARNING if necessary.
 
INITIAL-CONTENTS KEYMAP READ HIST DEFAULT-VALUE
 
INHERIT-INPUT-METHOD are `read-from-minibuffer's args."
 
  (cl-labels ((read () (read-from-minibuffer
 
                        prompt initial-contents keymap read hist
 
                        default-value inherit-input-method)))
 
    (let ((obj (read)))
 
      (when (and (equal obj "") default-value) (setq obj default-value))
 
      (while (not (funcall test obj))
 
        (message warning)
 
        (sit-for wg-minibuffer-message-timeout)
 
        (setq obj (read)))
 
      obj)))
 

	
 
(defun wg-read-new-workgroup-name (&optional prompt)
 
  "Read a non-empty name string from the minibuffer.
 
Print PROMPT"
 
  (let ((default (wg-new-default-workgroup-name)))
 
    (wg-read-object
 
     (or prompt (format "Name (default: %S): " default))
 
     (lambda (new) (and (stringp new)
 
                        (not (equal new ""))
 
                        (wg-unique-workgroup-name-p new)))
 
     "Please enter a unique, non-empty name"
 
     nil nil nil nil default)))
 

	
 
(defun wg-read-workgroup-index ()
 
  "Prompt for the index of a workgroup."
 
  (let ((max (1- (length (wg-workgroup-list-or-error)))))
 
    (wg-read-object
 
     (format "%s\n\nEnter [0-%d]: " (wg-workgroup-list-display) max)
 
     (lambda (obj) (and (integerp obj) (wg-within obj 0 max t)))
 
     (format "Please enter an integer [%d-%d]" 0 max)
 
     nil nil t)))
 

	
 
(defun wg-minibuffer-inactive-p ()
 
  "Return t when `minibuffer-depth' is zero, nil otherwise."
 
  (zerop (minibuffer-depth)))
 

	
 
(defun wg-barf-on-active-minibuffer ()
 
  "Throw an error when the minibuffer is active."
 
  (when (not (wg-minibuffer-inactive-p))
 
    (error "Exit minibuffer to use workgroups functions!")))
 

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

	
 
(defun wg-flag-workgroup-modified (workgroup)
 
  "Set WORKGROUP's and the current session's modified flags."
 
  (when wg-flag-modified
 
    (setf (wg-workgroup-modified workgroup) t)
 
    (setf (wg-session-modified (wg-current-session)) t)))
 

	
 
(defun wg-flag-session-modified (&optional session)
 
  "Set SESSION's modified flag."
 
  (when (and wg-flag-modified
 
             (or session (wg-current-session t)))
 
    (setf (wg-session-modified (or session (wg-current-session t))) t)))
 

	
 
(defun wg-flag-workgroup-modified (&optional workgroup)
 
  "Set WORKGROUP's and the current session's modified flags."
 
  (when wg-flag-modified
 
    (-when-let (or session (wg-current-session t))
 
      (setf (wg-session-modified it) t))))
 
    (setf (wg-workgroup-modified workgroup) t)
 
    (wg-flag-session-modified)))
 

	
 
(defun wg-current-workgroup (&optional noerror frame)
 
  "Return current workgroup in frame.
 
Error unless NOERROR, in FRAME if specified."
 
  (or wg-current-workgroup
 
      (aif (frame-parameter frame 'wg-current-workgroup-uid)
 
          (wg-find-workgroup-by :uid it noerror)
 
        (unless noerror (error "No current workgroup in this frame")))))
 

	
 
(defun wg-previous-workgroup (&optional noerror frame)
 
  "Return the previous workgroup in FRAME, or error unless NOERROR."
 
  (aif (frame-parameter frame 'wg-previous-workgroup-uid)
 
      (wg-find-workgroup-by :uid it noerror)
 
    (unless noerror (error "No previous workgroup in this frame"))))
 

	
 
(defun wg-set-current-workgroup (workgroup &optional frame)
 
  "Set the current workgroup to WORKGROUP in FRAME.
 
WORKGROUP should be a workgroup or nil."
 
  (set-frame-parameter frame 'wg-current-workgroup-uid
 
                       (when workgroup (wg-workgroup-uid workgroup))))
 

	
 
(defun wg-set-previous-workgroup (workgroup &optional frame)
 
  "Set the previous workgroup to WORKGROUP in FRAME.
 
WORKGROUP should be a workgroup or nil."
 
  (set-frame-parameter frame 'wg-previous-workgroup-uid
 
                       (when workgroup (wg-workgroup-uid workgroup))))
 

	
 
(defun wg-current-workgroup-p (workgroup &optional frame)
 
  "Return t when WORKGROUP is the current workgroup, nil otherwise."
 
  (awhen (wg-current-workgroup t frame)
 
    (eq workgroup it)))
 

	
 
(defun wg-previous-workgroup-p (workgroup &optional frame)
 
  "Return t when WORKGROUP is the previous workgroup, nil otherwise."
 
  (awhen (wg-previous-workgroup t frame)
 
    (eq workgroup it)))
 

	
 
(defun wg-get-workgroup (obj &optional noerror)
 
  "Return a workgroup from OBJ.
 
If OBJ is a workgroup, return it.
 
If OBJ is a string, return the workgroup named OBJ, or error unless NOERROR.
 
If OBJ is nil, return the current workgroup, or error unless NOERROR."
 
  (cond ((wg-workgroup-p obj) obj)
 
        ((stringp obj) (wg-find-workgroup-by :name obj noerror))
 
        ((null obj) (wg-current-workgroup noerror))
 
        (t (error "Can't get workgroup from type:: %S" (type-of obj)))))
 

	
 

	
 
;;; workgroup parameters
 
;;
 
;; Quick test:
 
;; (wg-workgroup-parameters (wg-current-workgroup))
 
;; (wg-set-workgroup-parameter (wg-current-workgroup) 'test1 t)
 
;; (wg-workgroup-parameter (wg-current-workgroup) 'test1)
 
(defun wg-workgroup-parameter (workgroup parameter &optional default)
 
  "Return WORKGROUP's value for PARAMETER.
 
If PARAMETER is not found, return DEFAULT which defaults to nil.
 
WORKGROUP should be accepted by `wg-get-workgroup'."
 
  (wg-aget (wg-workgroup-parameters (wg-get-workgroup workgroup))
 
           parameter default))
 

	
 
(defun wg-set-workgroup-parameter (parameter value &optional workgroup)
 
  "Set PARAMETER to VALUE in a WORKGROUP.
 
WORKGROUP should be a value accepted by `wg-get-workgroup'.
 
Return VALUE."
 
  (-when-let (workgroup (wg-get-workgroup (or workgroup (wg-current-workgroup t)) t))
 
    (wg-set-parameter (wg-workgroup-parameters workgroup) parameter value)
 
    (wg-flag-workgroup-modified workgroup)
 
    value))
 

	
 
(defun wg-remove-workgroup-parameter (parameter &optional workgroup)
 
  "Remove PARAMETER from WORKGROUP's parameters."
 
  (-when-let (workgroup (wg-get-workgroup workgroup t))
 
    (wg-flag-workgroup-modified workgroup)
 
    (wg-asetf (wg-workgroup-parameters workgroup) (wg-aremove it parameter))))
 

	
 
(defun wg-workgroup-local-value (variable &optional workgroup)
 
  "Return the value of VARIABLE in WORKGROUP.
 
WORKGROUP nil defaults to the current workgroup.  If there is no
 
current workgroup, or if VARIABLE does not have a workgroup-local
 
binding in WORKGROUP, resolve VARIABLE with `wg-session-local-value'."
 
  (let ((workgroup (wg-get-workgroup workgroup t)))
 
    (if (not workgroup) (wg-session-local-value variable)
 
      (let* ((undefined (cl-gensym))
 
             (value (wg-workgroup-parameter workgroup variable undefined)))
 
        (if (not (eq value undefined)) value
 
          (wg-session-local-value variable))))))
 
(defalias 'wg-local-value 'wg-workgroup-local-value)
 

	
 

	
 
(defun wg-workgroup-saved-wconfig-names (workgroup)
 
  "Return a new list of the names of all WORKGROUP's saved wconfigs."
 
  (mapcar 'wg-wconfig-name (wg-workgroup-saved-wconfigs workgroup)))
 

	
 
(defun wg-workgroup-get-saved-wconfig (wconfig-or-name &optional workgroup)
 
  "Return the wconfig by WCONFIG-OR-NAME from WORKGROUP's saved wconfigs.
 
@@ -4173,260 +4171,260 @@ that name and return it.  Otherwise error."
 
(defun wg-session-uids-consistent-p ()
 
  "Return t if there are no duplicate bufs or buf uids in the wrong places.
 
nil otherwise."
 
  (and (not (wg-dups-p (wg-buf-list) :key 'wg-buf-uid :test 'string=))
 
       (not (wg-dups-p (wg-workgroup-list) :key 'wg-workgroup-uid :test 'string=))))
 

	
 
(defun wg-find-session-file (filename)
 
  "Load a session visiting FILENAME, creating one if none already exists."
 
  (interactive "FFind session file: ")
 
  (cond ((file-exists-p filename)
 
         ;; TODO: handle errors when reading object
 
         (let ((session (read (f-read-text 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)))
 

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

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

	
 
(defun wg-write-sexp-to-file (sexp file)
 
  "Write the printable representation of SEXP to FILE."
 
  (with-temp-buffer
 
    (let ((print-level nil)  (print-length nil))
 
      (insert (format "%S" sexp)))
 
    (write-file file)))
 

	
 
;; FIXME: Duplicate buf names probably shouldn't be allowed.  An unrelated error
 
;; causes two *scratch* buffers to be present, triggering the "uids don't match"
 
;; error.  Write something to remove bufs with duplicate names.
 
(defun wg-perform-session-maintenance ()
 
  "Perform various maintenance operations on the current Workgroups session."
 
  (wg-update-current-workgroup-working-wconfig)
 

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

	
 
  ;; Garbage collection
 
  (let ((all-buf-uids (wg-all-buf-uids)))
 
    (wg-asetf (wg-buf-list)
 
              (cl-remove-if-not (lambda (uid) (member uid all-buf-uids)) it
 
                                :key 'wg-buf-uid)))
 
  (mapc 'wg-workgroup-gc-buf-uids (wg-workgroup-list))  ; Remove buf uids that have no referent in `wg-buf-list'
 
  (mapc 'wg-update-buffer-in-buf-list (wg-buffer-list-emacs)))
 

	
 
(defun wg-save-session-as (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."
 
  (interactive (list (read-file-name "Save session as: ")
 
                     (not current-prefix-arg)))
 
  (when (and confirm (file-exists-p filename))
 
    (unless (y-or-n-p (format "File `%s' exists; overwrite? " filename))
 
      (error "Cancelled")))
 
  (unless (file-writable-p filename)
 
    (error "File %s can't be written to" filename))
 
  (wg-perform-session-maintenance)
 
  (setf (wg-session-file-name (wg-current-session)) filename)
 
  (setf (wg-session-version (wg-current-session)) wg-version)
 

	
 
  ;; Save opened frames as a session parameter "frame-list".
 
  ;; Exclude `selected-frame' and daemon one (if any).
 
  ;; http://stackoverflow.com/questions/21151992/why-emacs-as-daemon-gives-1-more-frame-than-is-opened
 
  (if wg-control-frames
 
      (let ((fl (frame-list)))
 
        ;; TODO: remove using dash
 
        (mapc (lambda (frame)
 
                (if (string-equal "initial_terminal" (terminal-name frame))
 
                    (delete frame fl))) fl)
 
        (setq fl (delete (selected-frame) fl))
 
        (let (wg-flag-modified)
 
          (if (wg-current-session t)
 
              (wg-set-session-parameter 'frame-list (mapcar 'wg-frame-to-wconfig fl))))))
 
  (wg-write-sexp-to-file (wg-pickel-all-session-parameters) filename)
 
  (wg-mark-everything-unmodified)
 
  (wg-fontified-message (:cmd "Wrote: ") (:file filename)))
 
  (wg-fontified-message (:cmd "Wrote: ") (:file filename))
 
  (wg-mark-everything-unmodified))
 
(defalias 'wg-write-session-file 'wg-save-session-as)
 

	
 
(defun wg-get-session-file ()
 
  "Return the filename in which to save the session."
 
  (or (aif (wg-current-session t) (wg-session-file-name it))
 
      wg-session-file))
 
;;(read-file-name (format "Save session as [%s]: " wg-session-file))
 

	
 
(defun wg-save-session (&optional force)
 
  "Save the current Workgroups session if it's been modified.
 
When FORCE - save 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-save-session-as (wg-get-session-file))))
 

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

	
 
(defun wg-all-buf-uids (&optional session buffer-list)
 
  "Return the union of all SESSION buf-uids and BUFFER-LIST uids."
 
  (cl-union (cl-reduce 'wg-string-list-union  ; (wg-session-all-buf-uids session)
 
                       (wg-session-workgroup-list (or session (wg-current-session)))
 
                       :key 'wg-workgroup-all-buf-uids)
 
            ;; (wg-buffer-list-all-uids buffer-list)
 
            (delq nil (mapcar 'wg-buffer-uid (or buffer-list (wg-buffer-list-emacs))))
 
            :test 'string=))
 

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

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

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

	
 
(defun wg-set-session-parameter (parameter value &optional session)
 
  "Set PARAMETER to VALUE in SESSION.
 
SESSION nil means use the current session.  Return value."
 
  (let ((session (or session (wg-current-session))))
 
    (wg-set-parameter (wg-session-parameters session) parameter value)
 
    (wg-flag-session-modified session)
 
    value))
 

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

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

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

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

	
 
(defun wg-reload-session ()
 
  "Reload current workgroups session."
 
  (interactive)
 
  (let* ((file (wg-get-session-file))
 
         (exists (file-exists-p file)))
 
    (condition-case err
 
        (wg-open-session file)
 
      (progn
 
        (wg-create-first-wg)
 
        (message "Error loading session-file: %s" err))))
 
        ;; TODO: print what exactly happened
 
  (wg-create-first-wg))
 

	
 
(defun wg-save-session-on-emacs-exit ()
 
  "Call `wg-save-session-on-exit' with `wg-emacs-exit-save-behavior'.
 
Added to `kill-emacs-query-functions'."
 
  (wg-save-session-on-exit wg-emacs-exit-save-behavior) t)
 

	
 
(defun wg-save-session-on-workgroups-mode-exit ()
 
  "Call `wg-save-session-on-exit' with `wg-workgroups-mode-exit-save-behavior'.
 
Called when `workgroups-mode' is turned off."
 
  (wg-save-session-on-exit wg-workgroups-mode-exit-save-behavior) t)
 

	
 
(defun wg-pickel-all-session-parameters (&optional session)
 
  "Return a copy of SESSION after pickeling its parameters.
 
And the parameters of all its workgroups."
 
  (let ((copy (wg-copy-session (or session (wg-current-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))
 

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

	
 
(defun wg-workgroup-associated-buf-uids (&optional workgroup)
 
  "Return a new list containing all of WORKGROUP's associated buf uids."
 
  (awhen (or workgroup (wg-current-workgroup t))
 
    (append (wg-workgroup-strong-buf-uids it)
 
            (wg-workgroup-weak-buf-uids it))))
 

	
 
(defun wg-workgroup-associated-bufs (workgroup)
 
  "Return a new list containing all of WORKGROUP's associated bufs."
 
  (delete nil (mapcar 'wg-find-buf-by-uid
 
                      (wg-workgroup-associated-buf-uids workgroup))))
 

	
 
(defun wg-workgroup-associated-buffers (workgroup)
 
  "Return a new list containing all of WORKGROUP's associated buffer objects."
 
  (delete nil (mapcar 'wg-restore-buffer
 
                      (wg-workgroup-associated-bufs workgroup))))
 

	
 
(defun wg-workgroup-strongly-associate-bufobj (workgroup bufobj)
 
  "Strongly associate BUFOBJ with WORKGROUP."
 
  (let* ((uid (wg-bufobj-uid-or-add bufobj))
 
         (remp (wg-removef-p uid (wg-workgroup-weak-buf-uids workgroup)
 
                             :test 'string=))
 
         (addp (wg-pushnew-p uid (wg-workgroup-strong-buf-uids workgroup)
 
                             :test 'string=)))
 
    (when (or remp addp)
 
      (wg-flag-workgroup-modified workgroup)
0 comments (0 inline, 0 general)