Changeset - ad5ac55c1141
[Not reviewed]
0 6 0
Sergey Pashinin - 11 years ago 2014-08-23 12:10:21
sergey@pashinin.com
Replaced wg-aif
6 files changed with 11 insertions and 16 deletions:
0 comments (0 inline, 0 general)
src/workgroups-association.el
Show inline comments
 
@@ -85,91 +85,91 @@ WEAK non-nil means weakly associate it.  Otherwise strongly associate it."
 
(defun wg-auto-dissociate-buffer-hook ()
 
  "`kill-buffer-hook' that automatically dissociates buffers from workgroups."
 
  (when wg-dissociate-buffer-on-kill-buffer
 
    (wg-awhen (wg-current-workgroup t)
 
      (wg-workgroup-dissociate-bufobj it (current-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-associate-buffers (workgroup window-or-emacs-window-tree)
 
  "Associate the buffers visible in window elements of
 
WINDOW-OR-EMACS-WINDOW-TREE with the given WORKGROUP.
 
WINDOW-OR-EMACS-WINDOW-TREE must be either a window or a tree of
 
the form produced by `(car (window-tree))'."
 
  (wg-aif (windowp window-or-emacs-window-tree)
 
  (if (windowp window-or-emacs-window-tree)
 
      (with-current-buffer (window-buffer window-or-emacs-window-tree)
 
        (setq wg-buffer-workgroup workgroup))
 
    (dolist (w (cddr window-or-emacs-window-tree))
 
      (when w (wg-associate-buffers workgroup w)))))
 

	
 
(defun wg-workgroup-bufobj-association-type (workgroup bufobj)
 
  "Return BUFOBJ's association-type in WORKGROUP, or nil if unassociated."
 
  (let ((uid (wg-bufobj-uid-or-add bufobj)))
 
    (or (and (member uid (wg-workgroup-strong-buf-uids workgroup)) 'strong)
 
        (and (member uid (wg-workgroup-weak-buf-uids workgroup)) 'weak))))
 

	
 
(defun wg-associate-frame-buffers ()
 
  "Associate visible buffers with the current workgroup.
 
Unless it is currently being deactivated."
 
  (wg-awhen (wg-current-workgroup :noerror)
 
    (unless (member it wg-deactivation-list)
 
      (wg-associate-buffers it (car (window-tree))))))
 

	
 
;; (switch-to-buffer)   -> (read-buffer-to-switch "Asd")
 
;; -> internal-complete-buffer-except -> internal-complete-buffer
 
;; minibuffer-complete  minibuffer-completion-table
 
;; ido-switch-buffer  -> buffer-list
 
;;(global-set-key "\C-d" delete-char)
 
;; fdefinition
 
;; (buffer-list)
 
;; jit-lock-context-fontify
 
;; (wg-workgroup-weak-buf-uids (wg-current-workgroup))
 
;; (wg-workgroup-associated-buf-uids (wg-current-workgroup))
 
;; (wg-workgroup-associated-bufs (wg-current-workgroup))
 
;; (wg-workgroup-associated-buffers (wg-current-workgroup))
 
;; (wg-associate-frame-buffers)
 

	
 
;; (wg-workgroup-dissociate-all-buffers (wg-current-workgroup))
 
;;(fmakunbound 'buffer-list)
 
;;(define-key (current-global-map) [remap buffer-list] 'wg-buffer-list)
 
;; (wg-buffer-list)
 
;;(defun buffer-list (&optional frame)
 
;;  (list (current-buffer)))
 

	
 

	
 
(provide 'workgroups-association)
 
;;; workgroups-association.el ends here
src/workgroups-buf.el
Show inline comments
 
@@ -142,151 +142,151 @@ If BUF's file doesn't exist, call `wg-restore-default-buffer'"
 
(defun wg-bufobj-file-name (bufobj)
 
  "Return BUFOBJ's filename."
 
  (cl-etypecase bufobj
 
    (buffer (buffer-file-name bufobj))
 
    (wg-buf (wg-buf-file-name bufobj))
 
    (string (wg-bufobj-file-name (wg-get-buffer bufobj)))))
 

	
 
(defun wg-buf-major-mode (buf)
 
  "Return BUF's `major-mode'.
 
It's stored in BUF's local-vars list, since it's a local variable."
 
  (wg-aget (wg-buf-local-vars buf) 'major-mode))
 

	
 
(defun wg-buffer-major-mode (bufobj)
 
  "Return BUFOBJ's `major-mode'.
 
It works with Emacs buffer, Workgroups buffer object and a simple string."
 
  (cl-etypecase bufobj
 
    (buffer (wg-buffer-major-mode bufobj))
 
    (wg-buf (wg-buf-major-mode bufobj))
 
    (string (wg-buffer-major-mode bufobj))))
 

	
 
;; `wg-equal-bufobjs' and `wg-find-bufobj' may need to be made a lot smarter
 
(defun wg-equal-bufobjs (bufobj1 bufobj2)
 
  "Return t if BUFOBJ1 is \"equal\" to BUFOBJ2."
 
  (let ((fname1 (wg-bufobj-file-name bufobj1))
 
        (fname2 (wg-bufobj-file-name bufobj2)))
 
    (cond ((and fname1 fname2) (string= fname1 fname2))
 
          ((or fname1 fname2) nil)
 
          ((string= (wg-bufobj-name bufobj1) (wg-bufobj-name bufobj2)) t))))
 

	
 
(defun wg-find-bufobj (bufobj bufobj-list)
 
  "Find BUFOBJ in BUFOBJ-LIST, testing with `wg-equal-bufobjs'."
 
  (cl-find bufobj bufobj-list :test 'wg-equal-bufobjs))
 

	
 
(defun wg-find-bufobj-by-uid (uid bufobj-list)
 
  "Find the bufobj in BUFOBJ-LIST with uid UID."
 
  (cl-find uid bufobj-list :test 'string= :key 'wg-bufobj-uid))
 

	
 
(defun wg-find-buf-in-buf-list (buf buf-list)
 
  "Find BUF in BUF-LIST.
 
This is only here for completeness."
 
  (cl-find buf buf-list))
 

	
 
(defun wg-find-buffer-in-buffer-list (buffer-or-name buffer-list)
 
  "Find BUFFER-OR-NAME in BUFFER-LIST."
 
  (cl-find (wg-get-buffer buffer-or-name) buffer-list :key 'wg-get-buffer))
 

	
 
(defun wg-find-buffer-in-buf-list (buffer-or-name buf-list)
 
  "Find BUFFER-OR-NAME in BUF-LIST."
 
  (wg-aif (wg-buffer-uid buffer-or-name)
 
  (aif (wg-buffer-uid buffer-or-name)
 
      (wg-find-bufobj-by-uid it buf-list)
 
    (wg-find-bufobj buffer-or-name buf-list)))
 

	
 
(defun wg-find-buf-in-buffer-list (buf buffer-list)
 
  "Find BUF in BUFFER-LIST."
 
  (or (wg-find-bufobj-by-uid (wg-buf-uid buf) buffer-list)
 
      (wg-find-bufobj buf buffer-list)))
 

	
 
(defun wg-find-buf-by-uid (uid)
 
  "Find a buf in `wg-buf-list' by UID."
 
  (wg-find-bufobj-by-uid uid (wg-buf-list)))
 

	
 
(defun wg-set-buffer-uid-or-error (uid &optional buffer)
 
  "Set BUFFER's buffer local value of `wg-buffer-uid' to UID.
 
If BUFFER already has a buffer local value of `wg-buffer-uid',
 
and it's not equal to UID, error."
 
  (if wg-buffer-uid
 
      ;;(if (string= wg-buffer-uid uid) uid
 
      ;;  (error "uids don't match %S and %S" uid wg-buffer-uid))
 
      (setq wg-buffer-uid uid)))
 

	
 

	
 
(defun wg-buffer-special-data (buffer)
 
  "Return BUFFER's auxiliary serialization, or nil."
 
  (cl-some (lambda (fn) (funcall fn buffer)) wg-special-buffer-serdes-functions))
 

	
 

	
 
(defun wg-serialize-buffer-local-variables ()
 
  "Return an alist of buffer-local variable symbols and their values.
 
See `wg-buffer-local-variables-alist' for details."
 
  (wg-docar (entry wg-buffer-local-variables-alist)
 
    (wg-dbind (var ser des) entry
 
      (when (local-variable-p var)
 
        (cons var (if ser (funcall ser) (symbol-value var)))))))
 

	
 
(defun wg-buffer-to-buf (buffer)
 
  "Return the serialization (a wg-buf) of Emacs buffer BUFFER."
 
  (with-current-buffer buffer
 
    (wg-make-buf
 
     :name           (buffer-name)
 
     :file-name      (buffer-file-name)
 
     :point          (point)
 
     :mark           (mark)
 
     :local-vars     (wg-serialize-buffer-local-variables)
 
     :special-data   (wg-buffer-special-data buffer))))
 

	
 
(defun wg-add-buffer-to-buf-list (buffer)
 
  "Make a buf from BUFFER, and add it to `wg-buf-list' if necessary.
 
If there isn't already a buf corresponding to BUFFER in
 
`wg-buf-list', make one and add it.  Return BUFFER's uid
 
in either case."
 
  (with-current-buffer buffer
 
    (setq wg-buffer-uid
 
          (wg-aif (wg-find-buffer-in-buf-list buffer (wg-buf-list))
 
          (aif (wg-find-buffer-in-buf-list buffer (wg-buf-list))
 
              (wg-buf-uid it)
 
            (let ((buf (wg-buffer-to-buf buffer)))
 
              (push buf (wg-buf-list))
 
              (wg-buf-uid buf))))))
 

	
 
(defun wg-buffer-uid-or-add (buffer)
 
  "Return BUFFER's uid.
 
If there isn't already a buf corresponding to BUFFER in
 
`wg-buf-list', make one and add it."
 
  (or (wg-buffer-uid buffer) (wg-add-buffer-to-buf-list buffer)))
 

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

	
 

	
 

	
 
;;; buffer-list-filter commands
 

	
 
(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))
 
@@ -305,97 +305,97 @@ BUFFER nil defaults to `current-buffer'."
 
      (setf (wg-buf-uid new-buf) (wg-buf-uid old-buf))
 
      (wg-asetf (wg-buf-list) (cons new-buf (remove old-buf it))))))
 

	
 
(defun wg-update-buf-list (&optional buffer-list)
 
  "Update all bufs in `wg-buf-list' corresponding to buffers in BUFFER-LIST."
 
  (mapc 'wg-update-buffer-in-buf-list (or buffer-list (wg-buffer-list-emacs))))
 

	
 

	
 

	
 

	
 
(defun wg-buffer-list-display (buffer-list)
 
  "Return the BUFFER-LIST display string."
 
  (wg-display-internal
 
   'wg-buffer-display
 
   (if wg-center-rotate-buffer-list-display
 
       (wg-center-rotate-list buffer-list) buffer-list)))
 

	
 
(defun wg-buffer-list-filter-display (&optional workgroup blf-id)
 
  "Return a buffer-list-filter display string from WORKGROUP and BLF-ID."
 
  (wg-fontify
 
    "("
 
    (wg-workgroup-name (wg-get-workgroup workgroup))
 
    ":"
 
    (wg-get-buffer-list-filter-val blf-id 'indicator)
 
    ")"))
 

	
 
(defun wg-buffer-list-filter-prompt (prompt &optional workgroup blf-id)
 
  "Return a prompt string from PROMPT indicating WORKGROUP and BLF-ID."
 
  (wg-fontify
 
    prompt " "
 
    (wg-buffer-list-filter-display workgroup blf-id)
 
    ": "))
 

	
 
(defun wg-buffer-command-display (&optional buffer-list)
 
  "Return the buffer command display string."
 
  (concat
 
   (wg-buffer-list-filter-display) ": "
 
   (wg-buffer-list-display (or buffer-list (wg-filtered-buffer-list)))))
 

	
 

	
 
(defun wg-read-buffer (prompt &optional default require-match)
 
  "Workgroups' version of `read-buffer'.
 
Read with PROMT DEFAULT REQUIRE-MATCH."
 
  (if (not (wg-filter-buffer-list-p))
 
      (funcall (wg-read-buffer-function) prompt default require-match)
 
    (wg-with-buffer-list-filters 'read-buffer
 
      (funcall (wg-read-buffer-function)
 
               (wg-buffer-list-filter-prompt
 
                (wg-aif (string-match ": *$" prompt)
 
                (aif (string-match ": *$" prompt)
 
                    (substring prompt 0 it) prompt))
 
               default require-match))))
 

	
 

	
 

	
 
;;; filtered buffer-list construction
 

	
 
(defun wg-get-buffer-list-filter-id-flexibly (blf-id)
 
  "Return a buffer-list-filter-id one way or another."
 
  (or blf-id wg-current-buffer-list-filter-id 'all))
 

	
 
(defun wg-get-buffer-list-filter-val (id key &optional noerror)
 
  "Return ID's KEY's value in `wg-buffer-list-filter-definitions'.
 
Lots of possible errors here because
 
`wg-buffer-list-filter-definitions' can be modified by the user."
 
  (let ((slot-num (cl-case key (symbol 0) (indicator 1) (constructor 2))))
 
    (if (not slot-num)
 
        (unless noerror
 
          (error "`%S' is not a valid buffer-list-filter definition slot" key))
 
      (let* ((id (wg-get-buffer-list-filter-id-flexibly id))
 
             (entry (assq id (wg-local-value
 
                              'wg-buffer-list-filter-definitions))))
 
        (if (not entry)
 
            (unless noerror
 
              (error "`%S' is an undefined buffer-list-filter" id))
 
          (or (nth slot-num entry)
 
              (unless noerror
 
                (error "Slot `%S' is undefined in `%S's definition"
 
                       key id))))))))
 

	
 
(defun wg-filtered-buffer-list (&optional names workgroup bfl-id initial)
 
  "Return a filtered buffer-list from NAMES, WORKGROUP, BLF-ID and INITIAL.
 
NAMES non-nil means return a list of buffer-names instead of buffer objects.
 
WORKGROUP non-nil should be any workgroup identifier accepted by
 
`wg-get-workgroup'.
 
BLF-ID non-nil should be the identifier of a defined buffer-list-filter.
 
It defaults to `wg-get-buffer-list-filter-val'.
 
INITIAL non-nil should be an initial buffer-list to filter.  It defaults to
 
`wg-interesting-buffers'."
 
  (let ((buffer-list (funcall (wg-get-buffer-list-filter-val
 
                               (wg-get-buffer-list-filter-id-flexibly bfl-id)
 
                               'constructor)
 
                              (wg-get-workgroup workgroup)
 
                              (or initial (wg-interesting-buffers)))))
 
    (if names (mapcar 'wg-buffer-name buffer-list) buffer-list)))
 

	
 

	
 
;; buffer-list filters
src/workgroups-specialbufs.el
Show inline comments
 
@@ -11,97 +11,97 @@
 
(require 'workgroups-utils-basic)
 

	
 
(defcustom wg-special-buffer-serdes-functions
 
  '(wg-serialize-comint-buffer
 
    wg-serialize-speedbar-buffer)
 
  "Functions providing serialization/deserialization for complex buffers.
 

	
 
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)
 

	
 
;; Dired
 
(wg-support 'dired-mode 'dired
 
            `((deserialize . ,(lambda (buffer vars)
 
                                (when (or wg-restore-remote-buffers
 
                                          (not (file-remote-p default-directory)))
 
                                  (let ((d (wg-get-first-existing-dir)))
 
                                    (if (file-directory-p d) (dired d))))))))
 

	
 
;; `Info-mode'     C-h i
 
(wg-support 'Info-mode 'info
 
            `((save . (Info-current-file Info-current-node))
 
              (deserialize . ,(lambda (buffer vars)
 
                                ;;(with-current-buffer
 
                                ;;    (get-buffer-create (wg-buf-name buffer))
 
                                (wg-aif vars
 
                                (aif vars
 
                                    (if (fboundp 'Info-find-node)
 
                                        (apply #'Info-find-node it))
 
                                  (info)
 
                                  (get-buffer (wg-buf-name buffer)))))))
 

	
 
;; `help-mode'
 
;; Bug: https://github.com/pashinin/workgroups2/issues/29
 
(if nil
 
(wg-support 'help-mode 'help-mode
 
            `((save . (help-xref-stack-item help-xref-stack help-xref-forward-stack))
 
              (deserialize . ,(lambda (buffer vars)
 
                               (wg-dbind (item stack forward-stack) vars
 
                                 (condition-case err
 
                                     (apply (car item) (cdr item))
 
                                   (error (message "%s" err)))
 
                                 (wg-awhen (get-buffer "*Help*")
 
                                   (set-buffer it)
 
                                   (wg-when-boundp (help-xref-stack help-xref-forward-stack)
 
                                     (setq help-xref-stack stack
 
                                           help-xref-forward-stack forward-stack))))))))
 
)
 

	
 
;; ielm
 
(wg-support 'inferior-emacs-lisp-mode 'ielm
 
            `((deserialize . ,(lambda (buffer vars)
 
                                (ielm) (get-buffer "*ielm*")))))
 

	
 
;; Magit status
 
(wg-support 'magit-status-mode 'magit
 
            `((deserialize . ,(lambda (buffer vars)
 
                                (if (file-directory-p default-directory)
 
                                    (magit-status default-directory)
 
                                  (let ((d (wg-get-first-existing-dir)))
 
                                    (if (file-directory-p d) (dired d))))))))
 

	
 
;; Shell
 
(wg-support 'shell-mode 'shell
 
            `((deserialize . ,(lambda (buffer vars)
 
                                (shell (wg-buf-name buffer))))))
 

	
 
;; org-agenda buffer
 
(defun wg-get-org-agenda-view-commands ()
 
  "Return commands to restore the state of Agenda buffer.
 
Can be restored using \"(eval commands)\"."
 
  (interactive)
 
  (when (boundp 'org-agenda-buffer-name)
 
    (if (get-buffer org-agenda-buffer-name)
 
        (with-current-buffer org-agenda-buffer-name
src/workgroups-utils-basic.el
Show inline comments
 
;;; workgroups-utils.el --- Utilities used by Workgroups
 
;;; Commentary:
 
;;
 
;; A bunch of general purpose-ish utilities used by Workgroups.
 
;;
 
;;; Code:
 

	
 
;;; utils used in macros
 

	
 
(require 'cl-lib)
 
(require 'anaphora)
 
(require 'workgroups-faces)
 
(require 'workgroups-variables)
 

	
 
(defmacro wg-with-gensyms (syms &rest body)
 
  "Bind all symbols in SYMS to `gensym's, and eval BODY."
 
  (declare (indent 1))
 
  `(let (,@(mapcar (lambda (sym) `(,sym (cl-gensym))) syms)) ,@body))
 

	
 
(defmacro wg-dbind (args expr &rest body)
 
  "Bind the variables in ARGS to the result of EXPR and execute BODY.
 
Abbreviation of `destructuring-bind'."
 
  (declare (indent 2))
 
  `(cl-destructuring-bind ,args ,expr ,@body))
 

	
 
(defun wg-partition (list &optional n step)
 
  "Take LIST, return a list of N length sublists, offset by STEP.
 
N defaults to 2, and STEP defaults to N.
 
Iterative to prevent stack overflow."
 
  (let* ((n (or n 2)) (step (or step n)) acc)
 
    (while list
 
      (push (wg-take list n) acc)
 
      (setq list (nthcdr step list)))
 
    (nreverse acc)))
 

	
 

	
 

	
 
;;; bindings
 

	
 
(defmacro wg-if-let (cond-form then &rest else)
 
  "Bind VAR to the return value of COND.  If VAR is non-nil, do THEN.
 
Else do ELSE...
 

	
 
\(fn ((VAR COND) THEN ELSE...)"
 
  (declare (indent 2))
 
  `(let (,cond-form)
 
     (if ,(car cond-form) ,then ,@else)))
 

	
 
(defmacro wg-when-let (binds &rest body)
 
  "Like `let*' but when all BINDS are non-nil - eval BODY."
 
  (declare (indent 1))
 
  (wg-dbind (bind . binds) binds
 
    (when (consp bind)
 
      `(let (,bind)
 
         (when ,(car bind)
 
           ,(if (not binds) `(progn ,@body)
 
              `(wg-when-let ,binds ,@body)))))))
 

	
 
(defmacro wg-when-boundp (symbols &rest body)
 
  "When all SYMBOLS are bound, `eval' BODY."
 
  (declare (indent 1))
 
  `(when (and ,@(mapcar (lambda (sym) `(boundp ',sym)) symbols))
 
     ,@body))
 

	
 

	
 

	
 
;;; do-style wrappers
 

	
 
(defmacro wg-docar (spec &rest body)
 
  "do-style wrapper for `mapcar'.
 

	
 
\(fn (VAR LIST) BODY...)"
 
  (declare (indent 1))
 
  `(mapcar (lambda (,(car spec)) ,@body) ,(cadr spec)))
 

	
 
(defmacro wg-dohash (spec &rest body)
 
  "do-style wrapper for `maphash'.
 

	
 
\(fn (KEY VALUE TABLE [RESULT]) BODY...)"
 
  (declare (indent 1))
 
  (wg-dbind (key val table &optional result) spec
 
    `(progn (maphash (lambda (,key ,val) ,@body) ,table) ,result)))
 

	
 
(defmacro wg-doconcat (spec &rest body)
 
  "do-style wrapper for `mapconcat'.
 

	
 
\(fn (VAR SEQ [SEPARATOR]) BODY...)"
 
  (declare (indent 1))
 
  (wg-dbind (elt seq &optional sep) spec
 
    `(mapconcat (lambda (,elt) ,@body) ,seq (or ,sep ""))))
 

	
 

	
 

	
 
;;; anaphora
 

	
 
(defmacro wg-aif (test then &rest else)
 
  "Anaphoric `if'."
 
  (declare (indent 2))
 
  `(let ((it ,test)) (if it ,then ,@else)))
 

	
 
(defmacro wg-awhen (test &rest body)
 
  "Anaphoric `when'."
 
  (declare (indent 1))
 
  `(wg-aif ,test (progn ,@body)))
 
  `(aif ,test (progn ,@body)))
 

	
 
(defmacro wg-asetf (&rest places-and-values)
 
  "Anaphoric `setf'."
 
  `(progn ,@(mapcar (lambda (pv) `(let ((it ,(car pv))) (setf ,@pv)))
 
                    (wg-partition places-and-values 2))))
 

	
 

	
 

	
 
;;; other control structures
 

	
 
(defmacro wg-destructuring-dolist (spec &rest body)
 
  "Loop over a list.
 
Evaluate BODY, destructuring LIST into SPEC, then evaluate RESULT
 
to get a return value, defaulting to nil.  The only hitch is that
 
spec must end in dotted style, collecting the rest of the list
 
into a var, like so: (a (b c) . rest)
 

	
 
\(fn (SPEC LIST [RESULT]) BODY...)"
 
  (declare (indent 1))
 
  (wg-dbind (loopspec list &optional result) spec
 
    (let ((rest (cdr (last loopspec))))
 
      (wg-with-gensyms (list-sym)
 
        `(let ((,list-sym ,list))
 
           (while ,list-sym
 
             (wg-dbind ,loopspec ,list-sym
 
               ,@body
 
               (setq ,list-sym ,rest)))
 
           ,result)))))
 

	
 

	
 
;;; numbers
 

	
 
(defun wg-step-to (n m step)
 
  "Increment or decrement N toward M by STEP.
 
Return M when the difference between N and M is less than STEP."
 
  (cond ((= n m) n)
 
        ((< n m) (min (+ n step) m))
 
        ((> n m) (max (- n step) m))))
 

	
 
(defun wg-within (num lo hi &optional hi-inclusive)
 
  "Return t when NUM is within bounds LO and HI.
 
HI-INCLUSIVE non-nil means the HI bound is inclusive."
 
  (and (>= num lo) (if hi-inclusive (<= num hi) (< num hi))))
 

	
 
(defun wg-int-to-b36-one-digit (i)
 
  "Return a character in 0..9 or A..Z from I, and integer 0<=I<32.
 
Cribbed from `org-id-int-to-b36-one-digit'."
 
  (cond ((not (wg-within i 0 36))
 
@@ -266,97 +262,97 @@ KEYS is passed to `remove*'."
 
    (wg-move-elt elt list (mod (+ n pos) (length list)))))
 

	
 
(defun wg-cyclic-nth-from-elt (elt list n &rest keys)
 
  "Return the elt in LIST N places cyclically from ELT.
 
If ELT is not present is LIST, return nil.
 
KEYS is passed to `position'."
 
  (wg-when-let ((pos (apply 'cl-position elt list keys)))
 
    (wg-cyclic-nth list (+ pos n))))
 

	
 
(defun wg-util-swap (elt1 elt2 list)
 
  "Return a copy of LIST with ELT1 and ELT2 swapped.
 
Return nil when ELT1 and ELT2 aren't both present."
 
  (wg-when-let ((p1 (cl-position elt1 list))
 
                (p2 (cl-position elt2 list)))
 
    (wg-move-elt elt1 (wg-move-elt elt2 list p1) p2)))
 

	
 
(defun wg-dups-p (list &rest keys)
 
  "Return non-nil when LIST contains duplicate elements.
 

	
 
Keywords supported: :test :key
 

	
 
\(fn LIST [KEYWORD VALUE]...)"
 
  (let ((test (or (plist-get keys :test) 'eq))
 
        (key (or (plist-get keys :key) 'identity)))
 
    (cl-loop for (elt . rest) on list
 
             for elt = (funcall key elt)
 
             when (cl-find elt rest :test test :key key) return elt)))
 

	
 
(defun wg-string-list-union (&optional list1 list2)
 
  "Return the `union' of LIST1 and LIST2, using `string=' as the test.
 
This only exists to get rid of duplicate lambdas in a few reductions."
 
  (cl-union list1 list2 :test 'string=))
 

	
 

	
 

	
 
;;; alists
 

	
 
(defun wg-make-alist (&rest kvps)
 
  "Return a new alist from KVPS."
 
  (let (alist)
 
    (while kvps
 
      (push (cons (car kvps) (cadr kvps)) alist)
 
      (setq kvps (cddr kvps)))
 
    (nreverse alist)))
 

	
 
(defun wg-aget (alist key &optional default)
 
  "Return the value of KEY in ALIST. Uses `assq'.
 
If PARAM is not found, return DEFAULT which defaults to nil."
 
  (wg-aif (assq key alist) (cdr it) default))
 
  (aif (assq key alist) (cdr it) default))
 

	
 
(defun wg-acopy (alist)
 
  "Return a copy of ALIST's toplevel list structure."
 
  (mapcar (lambda (kvp) (cons (car kvp) (cdr kvp))) alist))
 

	
 
(defun wg-aput (alist key value)
 
  "Return a new alist from ALIST with KEY's value set to VALUE."
 
  (let* ((found nil)
 
         (new (wg-docar (kvp alist)
 
                (if (not (eq key (car kvp))) kvp
 
                  (setq found (cons key value))))))
 
    (if found new (cons (cons key value) new))))
 

	
 
(defun wg-aremove (alist key)
 
  "`remove' KEY's key-value-pair from ALIST."
 
  (remove (assoc key alist) alist))
 

	
 

	
 
;;; symbols and strings
 

	
 
(defun wg-toggle (symbol)
 
  "Toggle SYMBOL's truthiness."
 
  (set symbol (not (symbol-value symbol))))
 

	
 
(defun wg-symcat (&rest symbols-and-strings)
 
  "Return a new interned symbol by concatenating SYMBOLS-AND-STRINGS."
 
  (intern (mapconcat (lambda (obj) (if (symbolp obj) (symbol-name obj) obj))
 
                     symbols-and-strings "")))
 

	
 
(defun wg-make-string (times string &optional separator)
 
  "Like `make-string', but includes a separator."
 
  (mapconcat 'identity (make-list times string) (or separator "")))
 

	
 

	
 

	
 
;;; buffers
 

	
 
(defun wg-get-buffer (buffer-or-name)
 
  "Return BUFFER-OR-NAME's buffer, or error."
 
  (or (get-buffer buffer-or-name)
 
      (error "%S does not identify a buffer" buffer-or-name)))
 

	
 
(defun wg-buffer-name (buffer-or-name)
 
  "Return BUFFER-OR-NAME's `buffer-name', or error."
 
  (buffer-name (wg-get-buffer buffer-or-name)))
 

	
 
(defun wg-buffer-file-name (buffer-or-name)
 
  "Return BUFFER-OR-NAME's `buffer-file-name', or error."
src/workgroups-workgroup.el
Show inline comments
 
;;; workgroups-workgroup.el --- workgroup functions
 
;;; Commentary:
 
;;; Code:
 

	
 
(require 'ring)
 
(require 'workgroups-wconfig)
 
(require 'workgroups-minibuffer)
 

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

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

	
 
(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-current-workgroup (&optional noerror frame)
 
  "Return the current workgroup in FRAME, or error unless NOERROR."
 
  (or wg-current-workgroup
 
      (wg-aif (frame-parameter frame 'wg-current-workgroup-uid)
 
      (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."
 
  (wg-aif (frame-parameter frame 'wg-previous-workgroup-uid)
 
  (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.
 
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.
 
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."
 
  (wg-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."
 
  (wg-awhen (wg-previous-workgroup t frame)
 
    (eq workgroup it)))
 

	
 
(defmacro wg-with-current-workgroup (workgroup &rest body)
 
  "Execute forms in BODY with WORKGROUP temporarily current.
 
WORKGROUP should be any workgroup identifier accepted by
 
`wg-get-workgroup'.  The value returned is the last form
 
in BODY."
 
  (declare (indent 1))
 
  `(let ((wg-current-workgroup (wg-get-workgroup ,workgroup)))
 
     ,@body))
 

	
 
(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
 
;;
src/workgroups-wtree.el
Show inline comments
 
@@ -148,57 +148,57 @@ a 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-win-list (wtree)
 
  "Construct and return a list of all wg-wins in WTREE."
 
  (wg-flatten-wtree 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 (wg-aif (cl-find t wlist :key 'wg-win-selected)
 
                       :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))))
 

	
 

	
 

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