Emacs: buffer tabs

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:

;; Note: for tabbar 2.0 use 
;; tabbar-default not tabbar-default-face,
;; tabbar-selected not tabbar-selected-face,
;; tabbar-button not tabbar-button-face,
;; tabbar-separator not tabbar-separator-face
(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.

Edit: [2010-11-20] I like tabbar-mode but I also find myself using other buffer switching quite a bit. I'm using tabbar within a project, and ido-switch-buffer for moving between projects. I've changed the tabbar groups to show only buffers in the same directory:

(defun my-tabbar-buffer-groups (buffer)
  "Put files in the same directory into the same tab bar"
    (with-current-buffer (get-buffer buffer)
      (list (expand-file-name default-directory))))
(setq tabbar-buffer-groups-function 
      'my-tabbar-buffer-groups)

Update: [2017-09-24] I wanted to make the tabs look more like tabs in other apps, so I used powerline's "wave" separators with tabbar:

  (defvar my/tabbar-left "/" "Separator on left side of tab")
  (defvar my/tabbar-right "\\" "Separator on right side of tab")
  (defun my/tabbar-tab-label-function (tab)
    (powerline-render (list my/tabbar-left
                            (format " %s  " (car tab))
                            my/tabbar-right)))
  (with-eval-after-load 'powerline
    (setq my/tabbar-left (powerline-wave-right 'tabbar-default nil 24))
    (setq my/tabbar-right (powerline-wave-left nil 'tabbar-default 24))
    (setq tabbar-tab-label-function #'my/tabbar-tab-label-function)))

Labels:

Lisp vs. Python: Syntax

I've met lots of people who complain about Lisp and lots of people (especially Lisp folks) who complain about Python. Lisp is very elegant. There's something nice about its syntax (don't laugh!). The uniformity lets you do all sorts of neat things once you have macros. The basic syntactic construct in Lisp is the list, (a b c …), and it can mean lots of things:

  1. Sometimes (f x) is a function call, and f is the name of the function, and x is evaluated as an argument.
  2. Sometimes (f x) is a macro invocation, and f is the name of the macro, and x may be treated specially (it's up to the macro to decide).
  3. Sometimes (f x) is a binding. For example, (let ((f x)) …) binds a new variable f to the value x.
  4. Sometimes (f x) is a list of names. For example, (lambda (f x) …) creates a function that has parameters named f and x.
  5. Sometimes (f x) is a literal list. For example, (quote (f x)).
  6. Sometimes (f x) is interpreted in some other way because it's enclosed inside a macro. How it's interpreted depends on the macro definition.

The ability to use the same syntactic form for so many different things give you great power. You can define all sorts of cool things this way. I'm writing a pattern matcher that uses list expressions to define patterns and macros to interpret those list expressions. Macros are great for writing elegant, concise code.

The trouble is that you can't easily tell just by looking at (f x) how to interpret it. It could do anything. You'd think maybe a text editor like Emacs (which uses Lisp as its native language) would be able to help you in some way. But no. Emacs can't tell either. So how can you, the person reading the code, figure it out? Well, you can, but it takes a lot of effort. You can't determine the syntactic meaning of code (e.g., whether it's a definition or an expression) by looking at the code locally; you have to know a lot more of the program to figure it out. Lisp's syntactic strength is at the same time a weakness.

Python on the other hand has no macros and doesn't give you much to write concise, abstract, elegant code. There's a lot of repetition and many times it's downright verbose. But where Lisp is nice to write and hard to read, Python makes the opposite tradeoff. It's easy to read. You can determine how to interpret something—a string, a list, a function call, a definition—just by looking at the code locally. You never have to worry that somewhere in some other module someone defined a macro that changes the meaning of everything you're reading. By restricting what people can write, the job of the reader becomes easier.

Lisp seems to be optimized for writing code; Python seems to be optimized for reading it. Which you prefer may depend on how often you write new code vs. read unfamiliar code; I'm not entirely sure. What bothers me the most though is not that these two languages do different things, but that the people who argue about it seem to think that there is one “best” answer, and don't see that this is a tradeoff. When I'm writing code I prefer Lisp; when I'm reading code I prefer Python. I think this is an inherent tradeoff—any added flexibility for the writer means an added burden for the reader, and there is no answer that will be right for everyone.

–Amit

P.S. When I read debates online, I have a bias towards the people who view these things as tradeoffs and a bias against the people who say there's only one right answer and everyone else is stupid or clueless. This has sadly pushed me away from Lisp, the Mac, and other systems that I think are really good but have fanatical communities. When you're in a debate, consider that the other person might not be stupid, and there might be good reasons for his or her choices. You'll not only learn something about their position, but you'll be more likely get people to listen to you and adopt your point of view.

Update: [2012-06-29] Rich Hickey calls multiple uses of parentheses “overloading” in this talk.

Labels:

Emacs: color in shell buffers

In shell buffers inside Emacs (M-x shell), many programs want to use color in useful ways. For example, grep can highlight the portion of the line that matches the search pattern. Here's what I use to make Emacs and XEmacs show colors in shell windows:

;;; Shell mode
(setq ansi-color-names-vector ; better contrast colors
      ["black" "red4" "green4" "yellow4"
       "blue3" "magenta4" "cyan4" "white"])
(add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on)

I also use these settings to turn off word wrap and to make the prompt read-only:

(add-hook 'shell-mode-hook 
     '(lambda () (toggle-truncate-lines 1)))
(setq comint-prompt-read-only t)

Shell mode is handy but I find that I often just switch to a terminal window, mainly because I can pipe commands through less. If the output is very short, either Emacs or a terminal is fine. If it's of medium length, Emacs is usually nicer, since it lets me search and cut and paste easily. If the command has very long output, the terminal is nicer, because less lets me see just parts of the output. I haven't found a way in Emacs to deal with processes that output lots of lines.

Labels:

Emacs: better completion

Emacs already has decent completion capabilities. Any time there's a list of possible answers, you can press Tab for completion. When there's more than one possible completion, it brings up a list for you.

I like to see the list of possible completions without pressing Tab or ?. In XEmacs, I use two packages, iswitchb and icomplete to get a list of completions as I type, at least for switching buffers and for minibuffer inputs:

(require 'iswitchb)
(setq iswitchb-buffer-ignore '("^ " "*Buffer"))
(add-hook
 'iswitchb-define-mode-map-hook
 '(lambda ()
    (define-key iswitchb-mode-map " " 'iswitchb-next-match)
    (define-key iswitchb-mode-map [del] 'iswitchb-prev-match)
    (define-key iswitchb-mode-map [bs] 'iswitchb-prev-match)
    (define-key iswitchb-mode-map [right] 'iswitchb-next-match)
    (define-key iswitchb-mode-map [left] 'iswitchb-prev-match)))

(icomplete-mode 1)

In Emacs22, I use ido instead of iswitchb. It works for both switching buffers and for opening files:

(setq ido-confirm-unique-completion t)
(setq ido-default-buffer-method 'samewindow)
(setq ido-use-filename-at-point t)
(ido-mode t)
(ido-everywhere t)

(set-face-background 'ido-first-match "white")
(set-face-foreground 'ido-subdir "blue3")

(icomplete-mode 1)

If you're really into the power of completion, be sure to check out the icicles package by Drew Adams. It has a lot more features, and it has some things that look incredibly useful. It works for buffers, files, and the minibuffer, and it allows you to chain together multiple commands in powerful ways.

If icicles looks so good, why am I using ido and icomplete? It's because they come with Emacs22. The bar is higher for third party packages because it's an added dependency. I can't just tell a friend to put something into their .emacs; I have to tell them to download it and add to their load-path and so on. I wish there was a standard Emacs package system. I do plan to try out icicles and other packages once I've finished exploring the standard set of packages that comes with Emacs22.

Update [2015]: I now use helm, even though it's a third party dependency. Since I wrote this post in 2007, emacs added a package system so it's much easier to try out third party packages.

Labels:

Eliminate Time Zones

Regular readers of this blog know that I hate Daylight Saving Time. I also hate time zones, although to a lesser extent.

Take a look at Indiana. What time it is in Indiana depends on:

  • The date. The rules changed in 1942, 1945, 1949, 1957, 1961, 1966, 1968, 1969, 1973, 1974, 1975, …. They changed again as recently as March 11, 2007.
  • The county. The rules are different in each county.
  • The season. Some counties at some times have observed Daylight Saving Time.

(Thanks to Google Current for bringing this to my attention. Just watch the beginning.) What time it is in Indiana depends on Federal law, State law, and the choice of County. But the rules are so confusing that sometimes people just do their own thing.

Even worse, Indiana just can't win:

  • They want the state to be on the same time zone.
  • They want the northwest part of the state to match Chicago, which is Central Time.
  • They want the southeast part of the state to match Cincinnati, which is Eastern Time.

The only solution is for Chicago and Cincinnati to be on the same time zone.

Long ago every town had its own time. Time zones were introduced as rail travel became more common, and people interacted with others outside of their own town more often. As more of the country becomes connected through trade, transportation, the media, and the Internet, the burden of different people being on different times increases. Just as we switched from every town having its own time to every zone having its own time, I think we need to switch to the entire country having its own time (just like China and India and most of Western Europe). Eventually, as air and high-speed rail travel becomes commonplace and we begin to live in space colonies, we will have to abolish time zones altogether and use UTC.

Update: [2014-09-26] Watch this video if you want to get a sense of just how bad it is.

Labels: