9
votes

I converted from Visual Studio to Emacs for most of my development (mainly due to switching programming languages). However, there is one cool feature of Visual Studio that I truly miss: Ctrl-Tab between "buffers".

The ctrl-tab that in Visual Studio is not the same as C-x b in Emacs. So, it's not just a keyboard mapping issue. Here are the features of my ideal Ctrl-Tab:

  1. Hold down ctrl hit tab, you see the next buffer before you let go of ctrl.
  2. There is no need to hit enter.
  3. If this is not the buffer you want, hit tab again until you see the buffer you want.
  4. The moment that ctrl is released, the buffer ring is updated. The next buffer in the ring is the buffer where you first pressed ctrl.

I've seen some Emacs plugins that try to simulate this behavior, but #4 is the most difficult. It seems like Emacs is unable to detect when the ctrl key is released. Instead, the code waits for the user to be in the buffer for a certain time or waits for a buffer to change..and then the buffer is added to the ring. It's different enough to really frustrate me and just never use my beloved ctrl-tab again. For now I just deal with C-x b. ido-mode makes C-x b more tolerable, but I still dream of a day when I can ctrl-tab in emacs.

Has anyone out there found a way to configure Ctrl-Tab in Emacs to work like Visual Studio?

5
It looks very similar, but I'm not sure if they are the same. I specifically want the ring buffer to be modified when ctrl is released (not when the buffer is modified or after some timeout value). Sometimes I want to quickly read the contents of a buffer and go back to where I was. Emacs just can't do it..yet.User1
You're describing a stack like behavior like alt-tab in Windows. Why not use C-x left/right arrow to goto the next/prior buffer? You could map that down to a single key press (C-Tab, C-S-Tab).Demosthenex

5 Answers

5
votes

I was searching for exactly the behavior that you describe and came across the iflipb package: http://www.emacswiki.org/emacs/iflipb and bound it to C-tab, C-S-tab.

Unfortunately it doesn't restart the cycling either after releasing the ctrl key, so in that regard is the same as the my-switch-buffer in the answer above. Any new insights into this issue are highly appreciated.

4
votes

If you are using GNU Emacs 22.1 or more recent releases, \C-x<Right> fires M-x next-buffer and \C-x<Left> fires M-x previous-buffer. This page on EmacsWiki has a link to C-TAB Windows style buffer cycling. The page also talks about how to bring this behavior on older releases of Emacsen.

This question from yesterday looks very similar to what you want to achieve, except that the question talks about Notepad++ instead of Visual Studio.

2
votes

I think this is close to what you want. As you mentioned, Emacs doesn't receive events for the control key, so you can't quite get the functionality you want. However, this will not record the buffer switch until you do something other than press C-tab (i.e. scroll, type something, click the mouse, use a command M-x ...):

(global-set-key (kbd "<C-tab>") 'my-switch-buffer)
(defun my-switch-buffer ()
  "Switch buffers, but don't record the change until the last one."
  (interactive)
  (let ((blist (copy-sequence (buffer-list)))
        current
        (key-for-this (this-command-keys))
        (key-for-this-string (format-kbd-macro (this-command-keys)))
        done)
    (while (not done)
      (setq current (car blist))
      (setq blist (append (cdr blist) (list current)))
      (when (and (not (get-buffer-window current))
                 (not (minibufferp current)))
        (switch-to-buffer current t)
        (message "Type %s to continue cycling" key-for-this-string)
        (when (setq done (not (equal key-for-this (make-vector 1 (read-event)))))
          (switch-to-buffer current)
          (clear-this-command-keys t)
          (setq unread-command-events (list last-input-event)))))))
1
votes

I like the cycling and toggling behavior of iflipb too, it's very much like Windows Alt-Tab behavior. However, as previously pointed out, Emacs doesn't make it easy to notice when you release the control key. This makes toggling between the top two buffers imperfect: if you press C-Tab (and release) and then C-Tab (and release), you haven't toggled between the top two. Instead, iflipb just marches further down the buffer list. But if you perform any other Emacs command between the two C-Tab events, then iflipb recognizes that it is starting over in the buffer march, so it does the toggle.

On Windows, AutoHotKey can come to the rescue and send Emacs a keystroke when you release the control key. Here's my script:

#if WinActive("ahk_class Emacs")
^Tab::
Send {Blind}^{Tab}
SetTimer, WaitForCtrlUp, 10
return

WaitForCtrlUp:
if(!GetKeyState("LControl", "P") and !GetKeyState("RControl","P"))
{
    if WinActive("ahk_class Emacs")
        Send ^c:
    SetTimer, WaitForCtrlUp, Off
}
return

Whenever C-Tab is pressed in emacs, the script starts polling the state of the control key. When the key is released, it sends Emacs the C-c : key sequence. I have that key bound to a "null" command, which is enough to get iflipb to notice what's going on.

Here's the relevant .emacs excerpt:

; see http://www.emacswiki.org/emacs/iflipb
(require 'iflipb)

(global-set-key (kbd "<C-tab>") 'iflipb-next-buffer)
(global-set-key
 (if (featurep 'xemacs) (kbd "<C-iso-left-tab>") (kbd "<C-S-tab>"))
 'iflipb-previous-buffer)

(defun null-command ()
  "Do nothing (other than standard command processing such as remembering this was the last command executed)"
  (interactive))

(global-set-key "\C-c:" 'null-command)

So, it's kind of hacky, but it does work. Thanks to the posters at http://www.autohotkey.com/board/topic/72433-controltab/, who were trying to solve a similar problem.

1
votes

Add the following to your .emacs file:

(global-set-key (kbd "<C-tab>") 'next-buffer)