unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
From: Yuri Khan <yuri.v.khan@gmail.com>
To: "help-gnu-emacs@gnu.org" <help-gnu-emacs@gnu.org>
Subject: tabbar: Grouping buffers by windows
Date: Thu, 19 Sep 2013 22:06:59 +0700	[thread overview]
Message-ID: <CAP_d_8XxaZhf1FhGUSPtivRSLWhCL79uB+0h4fXgf-MFdLZQWg@mail.gmail.com> (raw)

Hello All,

I am using tabbar-mode to visualize my buffers. Additionally, I map
M-S-<left> and M-S-<right> to tabbar-backward-tab and
tabbar-forward-tab, respectively.

===
(global-set-key (kbd "M-S-<right>") 'tabbar-forward-tab)
(global-set-key (kbd "M-S-<left>") 'tabbar-backward-tab)
(tabbar-mode 1)
(tabbar-mwheel-mode 0)
===

In the default configuration, every window displays every tab. This
poses three problems:

* If the buffer I want is more than three tabs away from where I am, I
reach for the mouse, which is annoying.
* When the tabbar grows beyond the screen width, I cannot see all
tabs. I cannot choose which direction to go, and I cannot click
because the tab I want is offscreen and scrolling the tabbar is
cumbersome.
* I often split my frame into two windows, and I often have two or
three frames dedicated to different tasks. (For example, I might have
a separate frame where I do my .emacs.d customizations, a separate
frame for the program I’m writing (with one frame for a .h file and
another for .cpp), and a third frame for the library I’m using.) I
usually don’t want to mix buffers — in my mind, in most cases, each
buffer logically belongs to a single window in a single frame; a
buffer should show up in a different window only if I explicitly ask
for it.

Therefore, I want tabbar to show in each window only those tabs that
“belong” to that window.


After some trying and tweaking, I decided on the following heuristics
for the “belong” relationship:

* Each buffer remembers and maintains the last window where it was displayed.
* Each buffer also maintains a list of windows it is “pinned” to.
(Pinning and unpinning are explicit user commands.)
* Each window’s tabbar shows tabs for the buffer that is currently
displayed in that window, all buffers pinned to that window, and all
buffers that were last displayed in that window.


I have implemented this logic and it seems to work for me. I’d be glad
if somebody much more familiar with Elisp reviewed my code and gave
comments if I am doing something wrong or suboptimal.


Here’s the code from my init.el:

===
(defvar yk-buffer-last-window nil "Window the buffer was last displayed in")
(make-variable-buffer-local 'yk-buffer-last-window)

(defun yk-tabbar-window-configuration-change ()
  (setq yk-buffer-last-window (selected-window)))
(add-hook 'window-configuration-change-hook
'yk-tabbar-window-configuration-change)

(defadvice select-window (after yk-tabbar-select-window (window
&optional norecord))
  (with-current-buffer (window-buffer window)
    (setq yk-buffer-last-window window)))
(ad-activate 'select-window)


(defvar yk-buffer-pin-window-list nil "Windows the buffer is pinned to")
(make-variable-buffer-local 'yk-buffer-pin-window-list)

(defun yk-tabbar-pin-buffer ()
  "Pin the current buffer to the selected window."
  (interactive)
  (add-to-list 'yk-buffer-pin-window-list (selected-window) nil 'eq))

(defun yk-tabbar-unpin-buffer ()
  "Unpin the current buffer from the selected window."
  (interactive)
  (delq (selected-window) yk-buffer-pin-window-list))


;;; The buffer’s list of groups is, in this order:
;;; 1. The currently selected window, if it is displaying this buffer.
;;; 2. All other windows (if any) that are displaying this buffer.
;;; 3. The windows that this buffer is pinned to (if any).
;;; 4. The window that this buffer was last displayed in (if any).
;;; 5. The default group (always).
(defun yk-tabbar-buffer-groups ()
  (let* ((window (selected-window))
         (buffer (current-buffer))
         (windows (get-buffer-window-list buffer nil t)))
    (append
     (mapcar 'prin1-to-string
             (append (and (eq (window-buffer window) buffer) `(,window))     ; 1
                     (remq window windows)                                   ; 2
                     yk-buffer-pin-window-list                               ; 3
                     (and yk-buffer-last-window `(,yk-buffer-last-window)))) ; 4
     '("default"))))                                                         ; 5
(setq tabbar-buffer-groups-function 'yk-tabbar-buffer-groups)
===



                 reply	other threads:[~2013-09-19 15:06 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAP_d_8XxaZhf1FhGUSPtivRSLWhCL79uB+0h4fXgf-MFdLZQWg@mail.gmail.com \
    --to=yuri.v.khan@gmail.com \
    --cc=help-gnu-emacs@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).