Implement and document workspace tagging

Closes #15.
This commit is contained in:
Vasilij Schneidermann
2015-06-08 09:54:51 +02:00
parent b859805d63
commit 1779f48829
2 changed files with 88 additions and 39 deletions

View File

@ -46,6 +46,12 @@ window config on slot 2 is saved and the window config from slot 1 is
loaded. Try switching back and forth between them with ``C-c C-w '``
to get a feeling for how subsequent window manipulations are handled.
To make keeping track of workspaces easier, a tagging feature was
added. Use ``C-c C-w ,`` to set a tag for the current window config,
it will both appear in the modeline indicator and when using ``M-x
eyebrowse-switch-to-window-config``. Setting the tag to an empty
value will undo this change.
Key bindings
------------
@ -58,6 +64,7 @@ Key bind Function
``C-c C-w >`` Switch to next window config
``C-c C-w '`` Switch to last window config
``C-c C-w "`` Close current window config
``C-c C-w ,`` Rename current window config
``C-c C-w 0`` Switch to window config ``0``
\... ...
``C-c C-w 9`` Switch to window config ``9``
@ -109,8 +116,8 @@ This mode basically wraps what ``C-x r w`` and ``C-x r j`` do. The
difference is first, it saves and loads automatically for you upon
switching slots, and second, it doesn't overwrite the general purpose
registers. What it does instead is keeping its own data structure (a
list of lists containing slot, window config and point) and using it
to provide some other convenience keybinds, such as jumping to the
list of lists containing slot, window config, point and tag) and using
it to provide some other convenience keybinds, such as jumping to the
last window config or the next one available.
Contributing

View File

@ -37,6 +37,7 @@
;;; Code:
(require 'dash)
(require 'format-spec)
;; variables
@ -147,6 +148,24 @@ t: Clean up and display the scratch buffer."
:type 'hook
:group 'eyebrowse)
(defcustom eyebrowse-slot-format "%s"
"Format string for untagged slots.
The following format codes are supported:
%s: Current slot"
:type 'string
:group 'eyebrowse)
(defcustom eyebrowse-tagged-slot-format "%s:%t"
"Format string for tagged slots.
The following format codes are supported:
%t: Tag
%s: Current slot"
:type 'string
:group 'eyebrowse)
(defvar eyebrowse-mode-map
(let ((map (make-sparse-keymap)))
(let ((prefix-map (make-sparse-keymap)))
@ -154,6 +173,7 @@ t: Clean up and display the scratch buffer."
(define-key prefix-map (kbd ">") 'eyebrowse-next-window-config)
(define-key prefix-map (kbd "'") 'eyebrowse-last-window-config)
(define-key prefix-map (kbd "\"") 'eyebrowse-close-window-config)
(define-key prefix-map (kbd ",") 'eyebrowse-rename-window-config)
(define-key prefix-map (kbd "0") 'eyebrowse-switch-to-window-config-0)
(define-key prefix-map (kbd "1") 'eyebrowse-switch-to-window-config-1)
(define-key prefix-map (kbd "2") 'eyebrowse-switch-to-window-config-2)
@ -171,19 +191,6 @@ t: Clean up and display the scratch buffer."
;; functions
;; NOTE: window configurations are at the moment a list of a list
;; containing the numerical slot, window configuration and point. To
;; add "tagging", it would be useful to save a tag as fourth component
;; and display it if present, not only in the mode line, but when
;; renaming and selecting a window configuration interactively, too.
;; This obviously requires an interactive window switching command.
;; NOTE: The display of the tag should be configurable via format
;; string and that format string be able to resemble vim tabs, i3
;; workspaces, tmux sessions, etc. Therefore it has to contain format
;; codes for slot, tag and buffer name. A suitable formatting
;; function can be found in s.el.
(defun eyebrowse--get (type &optional frame)
"Retrieve frame-specific value of TYPE.
If FRAME is nil, use current frame. TYPE can be any of
@ -215,7 +222,7 @@ If FRAME is nil, use current frame. TYPE can be any of
(eyebrowse--set 'last-slot 1 frame)
(eyebrowse--set 'current-slot 1 frame)
(eyebrowse--insert-in-window-config-list
(eyebrowse--current-window-config 1) frame)))
(eyebrowse--current-window-config 1 "") frame)))
(defun eyebrowse--update-window-config-element (new-element)
"Replace the old element with NEW-ELEMENT in the window config list.
@ -236,9 +243,9 @@ This function keeps the sortedness intact."
"Non-nil if there is a window config at SLOT."
(assq slot (eyebrowse--get 'window-configs frame)))
(defun eyebrowse--current-window-config (slot)
(defun eyebrowse--current-window-config (slot tag)
"Returns a window config list appliable for SLOT."
(list slot (current-window-configuration) (point)))
(list slot (current-window-configuration) (point) tag))
(defun eyebrowse--load-window-config (slot)
"Restore the window config from SLOT."
@ -250,14 +257,18 @@ This function keeps the sortedness intact."
(goto-char point)))))
(defun eyebrowse--read-slot (&optional initial-slot)
(let* ((candidates (--map (number-to-string (car it))
"Read in a window config SLOT to switch to.
A formatted list of window configs is presented as candidates.
If INITIAL-SLOT is set, use the respective window config as
preselected candidate."
(let* ((candidates (--map (cons (eyebrowse-format-slot it)
(car it))
(eyebrowse--get 'window-configs)))
(selection (completing-read
"Enter slot: " candidates
nil nil (and initial-slot (number-to-string initial-slot))))
(slot (string-to-number selection)))
(unless (and (= slot 0) (not (string= selection "0")))
slot)))
(candidate (completing-read
"Enter slot: " candidates nil t
(and initial-slot
(car (rassoc initial-slot candidates))))))
(cdr (assoc candidate candidates))))
(defun eyebrowse-switch-to-window-config (slot)
"Switch to the window config SLOT.
@ -266,20 +277,24 @@ This will save the current window config to
`eyebrowse-switch-back-and-forth' is t and
`eyebrowse-current-slot' equals SLOT, this will switch to the
last window config."
(interactive (list (eyebrowse--read-slot (eyebrowse--get 'last-slot))))
(interactive (list (if (numberp current-prefix-arg)
current-prefix-arg
(eyebrowse--read-slot (eyebrowse--get 'last-slot)))))
(when slot
(let ((current-slot (eyebrowse--get 'current-slot))
(last-slot (eyebrowse--get 'last-slot)))
(let* ((current-slot (eyebrowse--get 'current-slot))
(window-configs (eyebrowse--get 'window-configs))
(current-tag (nth 3 (assoc current-slot window-configs)))
(last-slot (eyebrowse--get 'last-slot)))
(when (and eyebrowse-switch-back-and-forth (= current-slot slot))
(setq slot last-slot))
(let ((new-window-config (not (eyebrowse--window-config-present-p slot))))
(when (/= current-slot slot)
(run-hooks 'eyebrowse-pre-window-switch-hook)
(eyebrowse--update-window-config-element
(eyebrowse--current-window-config current-slot))
(eyebrowse--current-window-config current-slot current-tag))
(when new-window-config
(eyebrowse--insert-in-window-config-list
(eyebrowse--current-window-config slot)))
(eyebrowse--current-window-config slot "")))
(eyebrowse--load-window-config slot)
(eyebrowse--set 'last-slot current-slot)
(eyebrowse--set 'current-slot slot)
@ -358,6 +373,23 @@ another appropriate window config."
(eyebrowse-next-window-config nil))
(eyebrowse--delete-window-config (eyebrowse--get 'last-slot)))))
(defun eyebrowse-rename-window-config (slot)
"Rename the window config at SLOT.
When used interactively, default to the current window config,
use the prefix argument to prompt for a slot or a numerical
prefix argument to select a slot by its number."
(interactive (list (cond
((consp current-prefix-arg)
(eyebrowse--read-slot))
((numberp current-prefix-arg)
current-prefix-arg)
(t (eyebrowse--get 'current-slot)))))
(let* ((window-configs (eyebrowse--get 'window-configs))
(window-config (assoc slot window-configs))
(current-tag (nth 3 window-config))
(tag (read-string "Tag: " current-tag)))
(setf (nth 3 window-config) tag)))
;; NOTE I've tried out generating the respective commands dynamically
;; with a macro, but this ended in unreadable code and Emacs not being
;; able to locate the generated commands, using lexical binding and a
@ -449,7 +481,16 @@ is detected, extra key bindings will be set up with
(define-key map (kbd "M-8") 'eyebrowse-switch-to-window-config-8)
(define-key map (kbd "M-9") 'eyebrowse-switch-to-window-config-9)))
(defun eyebrowse--update-mode-line ()
(defun eyebrowse-format-slot (window-config)
(let* ((slot (car window-config))
(tag (nth 3 window-config))
(format-string (if (and tag (> (length tag) 0))
eyebrowse-tagged-slot-format
eyebrowse-slot-format)))
(format-spec format-string
(format-spec-make ?s slot ?t tag))))
(defun eyebrowse-mode-line-indicator ()
"Return a string representation of the window configurations."
(let* ((left-delimiter (propertize eyebrowse-mode-line-left-delimiter
'face 'eyebrowse-mode-line-delimiters))
@ -458,10 +499,7 @@ is detected, extra key bindings will be set up with
(separator (propertize eyebrowse-mode-line-separator
'face 'eyebrowse-mode-line-separator))
(current-slot (eyebrowse--get 'current-slot))
(active-item (propertize (number-to-string current-slot)
'face 'eyebrowse-mode-line-active))
(window-configs (eyebrowse--get 'window-configs))
(window-config-slots (mapcar 'car window-configs)))
(window-configs (eyebrowse--get 'window-configs)))
(if (and eyebrowse-mode-line-style
(not (eq eyebrowse-mode-line-style 'hide))
(or (and (not (eq eyebrowse-mode-line-style 'smart))
@ -471,9 +509,13 @@ is detected, extra key bindings will be set up with
(concat
left-delimiter
(mapconcat
(lambda (n) (if (= n current-slot) active-item (number-to-string n)))
window-config-slots
separator)
(lambda (window-config)
(let ((slot (car window-config))
(caption (eyebrowse-format-slot window-config)))
(if (= slot current-slot)
(propertize caption 'face 'eyebrowse-mode-line-active)
caption)))
window-configs separator)
right-delimiter)
"")))
@ -494,7 +536,7 @@ behaviour of `ranger`, a file manager."
(eyebrowse-init)
(add-hook 'after-make-frame-functions 'eyebrowse-init)
(unless (assoc 'eyebrowse-mode mode-line-misc-info)
(push '(eyebrowse-mode (:eval (eyebrowse--update-mode-line)))
(push '(eyebrowse-mode (:eval (eyebrowse-mode-line-indicator)))
(cdr (last mode-line-misc-info)))))
(remove-hook 'after-make-frame-functions 'eyebrowse-init)))