Tabs to show overlapping windows are becoming more common these days, especially in terminals, browsers, and chat programs. The idea is that a single window can contain several … buffers. Emacs already has this, and has had this for a long time. It's just that by default Emacs doesn't have visible tabs to show the buffers. XEmacs and SXEmacs can show tabs with “buffer tabs”; for GNU Emacs 21 you need to install TabBar mode (thanks to Jemima for finding this), which gives you tabs like this:

screenshot of tabbar-mode

Well, it doesn't look like that by default. The standard settings give each tab a 3d button appearance. I wanted something simpler, so I changed the settings:

  (set-face-attribute
   'tabbar-default-face nil
   :background "gray60")
  (set-face-attribute
   'tabbar-unselected-face nil
   :background "gray85"
   :foreground "gray30"
   :box nil)
  (set-face-attribute
   'tabbar-selected-face nil
   :background "#f2f2f6"
   :foreground "black"
   :box nil)
  (set-face-attribute
   'tabbar-button-face nil
   :box '(:line-width 1 :color "gray72" :style released-button))
  (set-face-attribute
   'tabbar-separator-face nil
   :height 0.7)

  (tabbar-mode 1)
  (define-key global-map [(alt j)] 'tabbar-backward)
  (define-key global-map [(alt k)] 'tabbar-forward)

This makes the currently selected tab match my default background (#f2f2f6), removes the 3d borders, and adds a bit of space between the tabs. I also define Alt-j and Alt-k to switch tabs; I use the same keys in other tabbed apps, because they're easier to type than moving my hands to the arrow keys.

TabBar-mode looks neat, but I'm not sure how useful it will be. In Emacs I have lots of buffers—more than will fit as tabs. The main thing I like so far are the keys for cycling between related buffers, but as the number of buffers grows it becomes faster to switch directly to the buffer I want.

Labels:

20 comments:

will wrote at May 01, 2007 7:18 AM

I think there are a couple of extra right-parens in there.

But this is really cool--I'm psyched you wrote about it.

Amit wrote at May 01, 2007 8:37 AM

Yes, you're right -- I've fixed the parentheses. Thanks!

Bas wrote at May 01, 2007 2:23 PM

Also be sure to check out the excellent IDO package, which as an example makes it so much easier to switch buffers (when you have many open).

Amit wrote at May 01, 2007 3:51 PM

In addition to ido, I've also tried out iswitchb and isearchb. Isearchb is the most interesting in that it's like isearch, but for switching buffers. It switches buffers as you type, and you don't have to press RET to get out. I just haven't used it enough to get used to it yet.

All three of these are included with GNU Emacs 22.

Anonymous wrote at July 25, 2007 6:41 PM

Just out of curiosity, how many buffers do you usually use? Ever since I've started using desktop, I don't think I've ever had below a hundred buffers open on my laptop - maybe fifty or so at work. It's a ridiculously large number for most editors, but with the buffer switch modes you went over, it's absolutely manageable. Is it typical, though?

Amit wrote at July 25, 2007 11:54 PM

Although I use desktop, I tend to keep few buffers open at once (maybe 10–20), and use recent file history to reopen them. I'm not using tabbar right now; I'm experimenting with icicles. However I'm still not happy and continue to experiment.

Anonymous wrote at October 03, 2007 10:20 AM

tabbar-mode has the concept of groups so you don't see all buffers at once.

What font are you using at the screenshot (in the buffer, not the tabbar)?

Amit wrote at October 05, 2007 8:46 PM

I did try groups but eventually gave up on tabbar. I found it changed the behavior of killing buffers. Normally, if you're in A, then visit B, then kill B, you go back to A, but with tabbar, it would choose some other buffer. That was annoying enough that I stopped using tabbar.

The buffer font in the screenshot is Monaco (on the Mac). These days I use DejaVu Sans Mono.

pradeep wrote at April 08, 2008 6:21 AM

Hi amit,

Iam using xemacs-21.4.14
I have options->display->buffers tab visible set
Even then my xemacs is not showing buffers, any comment.

u can reply to pradeep.buddy@gmail.com

ritesh wrote at April 26, 2008 11:20 PM

Is there a way to get tabs through the GUI, like you have in gvim, V.7 and up? It would be so much more convenient to have multiple tabs instead of multiple frames. The lisp-based solution mentioned here doesn't appeal to me too much :(
For sentimental reasons (!!), I build my apps (Emacs, Gvim, etc) with Motif. I'd looked at the motif code for gvim, but X-window programming is something i'm totally unfamiliar with. And, in Emacs's case, there's elisp on top of everything else.

Amit wrote at April 27, 2008 9:20 AM

Interactively, you can use M-x tabbar-mode. The Lisp I pasted was because I didn't like the defaults and wanted to customize it.

gvim's tabs look nicer because they're gtk tabs, whereas Emacs is more cross platform and has tabs on many different systems. Emacs is pretty old fashioned in this regard.

Saurabh wrote at August 28, 2008 3:26 PM

when i tried to load the library it gave this error.
No such face tabbar-seperator face
any idea what the problem is.

Amit wrote at August 28, 2008 6:45 PM

Saurabh, what version of tabbar-mode do you have? I posted this blog entry over a year ago so it's possible something has changed in a newer version of tabbar-mode. I have version 1.2, written in 2003 by David Ponce.

Tom wrote at September 25, 2008 5:47 PM

I had problems too, using tabbar 2.0. I think a fair amount has changed, shame the defaults suck :(

Anonymous wrote at October 07, 2008 7:13 AM

I like your cosmetic changes. I think it's an improvement.

Saurabh wrote at August 28, 2008 3:27 PM

After I loaded the tabbar-library this is what i get.

No such face tabbar-seperator face

whocares wrote at November 21, 2008 7:30 AM

;; maybe you will find this usefull
;; it moves the current tab left/right rearranging the
;; tabs (as in konsole for example)
;; beware, this is my first elisp(lisp) hack
;; it probably looks terrible

(defun tabbar-move-tab (&optional right)
"Move current tab to the left or to the right
if RIGHT is set."
(let* ((ctabset nil)
(ctabs nil)
(ctab nil)
(hd nil)
(tl nil))
(and
(setq ctabset (tabbar-current-tabset 't))
(setq ctabs (tabbar-tabs ctabset))
(setq ctab (tabbar-selected-tab ctabset))
(setq tl ctabs)
(setq hd '())) ;; nil
(while (and (cdr tl) (not (eq ctab (car tl))) (not (eq ctab (cadr tl))))
(setq hd (append hd (list (car tl)))
tl (cdr tl)))
(set ctabset
(cond
((and (not right) (null hd) (eq ctab (car tl)))
(append (cdr tl) (list (car tl))))
((not right)
(append hd (list (cadr tl)) (list (car tl)) (cddr tl)))
((and right (not (cddr tl)))
(append (list (cadr tl)) hd (list (car tl))))
((and right (eq ctab (car tl)))
(append hd (list (cadr tl)) (list (car tl)) (cddr tl)))
(right
(append hd (list (car tl)) (list (caddr tl)) (list (cadr tl)) (cdddr tl)))
))
(put ctabset 'template nil)
(tabbar-display-update)))

(defun tabbar-move-tab-left ()
"Move tab left."
(interactive)
(tabbar-move-tab))

(defun tabbar-move-tab-right ()
"Move tab right."
(interactive)
(tabbar-move-tab))

宋时歌 wrote at November 23, 2008 3:21 PM

Looks really cool, much better than the default. Thanks.

Shige

geekd wrote at July 22, 2009 11:33 AM

If you are using tabbar 2.0, and Amit's code doesn't work for you, just remove the -face off of each of Amit's statements. For example:

'tabbar-default-face nil
becomes
'tabbar-default nil

and then it will work.

good luck!
-geekd

Anonymous wrote at July 26, 2009 8:04 PM

Thanks whocares. Works great with one minor change.
tabbar-move-tab-right should be:
(defun tabbar-move-tab-right ()
"Move tab right."
(interactive)
(tabbar-move-tab t))

Post a Comment