Skip to content
Switching buffers and buffer groups at will in emacs. Based on MTorus : rewritten from scratch
Branch: master
Clone or download
Latest commit 55e5428 Mar 15, 2019
Type Name Latest commit message Commit time
Failed to load latest commit information.
Makefile rm Mar 15, 2019

Table of contents


If you ever dreamed about creating and switching buffer groups at will in Emacs, Torus is the tool you want.

In short, this plugin let you organize your buffers by creating as many buffer groups as you need, add the buffers you want to it and quickly navigate between :

  • Buffers of the same group
  • Buffer groups
  • Workspaces, ie sets of buffer groups

Note that :

  • A location is a pair (filename . position)
  • A buffer group, in fact a location group, is called a circle
  • A set of buffer groups is called a torus (a circle of circles)


This project is inspired by MTorus. You can find the original sources on the links below :

The code I forked is complex, so I decided to write a new version from scratch, easier to maintain and enjoying more recent features of emacs.


Torus helps you to organize your files in groups that you create yourself, following your workflow. You only add the files you want, where you want. For instance, if you have a “organize” group with agenda & todo files, you can quickly alternate them, or display them in two windows. Then, if you suddenly got an idea to tune emacs, you switch to the “emacs” group with your favorites configuration files in it. Same process, to cycle, alternate or display the files. Note that the torus containing all these groups can be saved on a file and loaded later. Over time, your groups will grow and adapt to your style.



Torus is available on MELPA. If you have this line on your init file :

(add-to-list 'package-archives '("melpa" . ""))

you should be able to install it from the packages menu (M-x list-packages).


If you use el-get, just create a recipe file torus.rcp :

(:name torus
	 :website ""
	 :description "Torus : Circle of Circles of buffers"
	 :type github
	 :pkgname "chimay/torus")

and add it to a directory present in el-get-recipe-path. Then, use M-x el-get-install <RET> torus or add :

(el-get-bundle torus)

to your init file.

Step by Step

First Circles

Let’s say we have the files Juice, Tea, Coffe. The first thing to do is to create a group (a circle) which will contain them. So, we launch torus-add-circle and answer Drinks to the prompt. Then, we go to Juice and use torus-add-location to add it to the circle. Same process with Tea and Coffee. We now have a circle Drink containing three files.

If your files are not already opened in buffers, just use torus-add-file to add them in the circle.

If you want to create another circle, let’s say Fruits, simply launch torus-add-circle again, and enter another name. You can then add the files Apple, Pear and Orange to it. You can even also add Juice, a file can be added to more than one circle.

Now, suppose that in the Juice file, you have a Pineapple and a Mango sections, and you want to compare them. Just go to the Pineapple section, use torus-add-location. It will add the location (Juice . pineapple-position) to the current circle. Then, go to the Mango section, and do the same. The (Juice . mango-position) will also be added to the circle. You can then easily alternate both, or display them in split windows.

Moving around

You can cycle the files of a circle with torus-next-location and torus-previous-location. You can also switch file with completion by using torus-switch-location. It works well with Helm.

To cycle the circles, use torus-next-circle and torus-previous-circle. To go to a given circle with completion, use torus-switch-circle.

Square the Circle

Over time, the number of circles will grow. Completion is great, but if you just want to alternate the two last circles in history, you’ll probably prefer ŧorus-alternate-circles. You can also alternate two last files inside the same circle with torus-alternate-in-same-circle. So, you have the square :

circle 1, file 1circle 1, file 2
circle 2, file 3circle 2, file 4

at your fingertips.

Finally, torus-alternate-in-same-torus alternate two last history files, regardless of their circles.


If you prefix a torus navigation function by C-u, the asked file will be opened in a new window below. With C-u C-u, it will be in a new window on the right.

If you want to see all the circle files in separate windows, use torus-layout-menu and chose between horizontal, vertical or grid splits. You also have layouts with main window on left, right, top or bottom side.

Your choice is remembered by torus for the current circle. You can swith back to one window using the same layout function. The special choice “manual” ask Torus not to interfere in your layout.

The maximum number of windows generated by the split functions are conxtrolled by the vars torus-maximum-horizontal-split and torus-maximum-vertical-split.

Key Bindings

All bindings are available after the prefix key <super-t> by default. You can see them by pressing <super-t><C-h>, or by installing which-key. You can also define your own :

(define-key torus-map (kbd "i") 'torus-info)


The option torus-binding-level, an integer between 0 and 3, decide how many functions will be bound to keys : the higher it is, the more bindings available. Level 1 or 2 is fine for most usages.

  • Level 0
    • Adding
    • Deleting
    • Moving around
    • Save and load
  • Level 1
    • History
    • Renaming
    • Moving and copying things
    • Join
    • Layout
  • Level 2
    • Reverse
    • Prefix
    • Autogroup
  • Level 3 : you surely don’t want to use these
    • Print main internal variables
    • Reset main internal variables
    • Miscellaneous

List of bindings

Enter the prefix key, then :

  • c : create a new circle, add it to the torus
  • l : create the current location (file . position) to the current circle
  • f : add a file to the current circle ; more precisely, location (file . 1)
  • i : info about the current circle
  • p : print main variables content
  • <down> : next file (location) in circle
  • <up> : previous file in circle
  • = : switch file in circle
  • <right> : next circle
  • <left> : previous circle
  • <space> : switch circle
  • s : search file in all circles
  • <PageDown> : older file in file history
  • <PageUp> : newer file in file history
  • a : alternate menu
    • m : alternate last two visited files in all toruses (meta torus)
    • t : alternate last two visited files in current torus
    • c : alternate last two visited files in current circle
    • T : alternate last two toruses
    • C : alternate last two circles
  • ^ : alternate last two visited files in history of current torus
  • < : alternate last two circles in history
  • > : alternate last two files in same circle in history
  • h : search in the file history
  • n : rename circle
  • d : delete file from circle
  • D : delete circle from torus
  • w : write torus to a file as Lisp code (with “.el” extension)
  • r : read torus from a torus file
  • e : edit a torus file ; ask to load its content after saving it
  • m : move file in circle (not on disk)
  • M : move circle in torus
  • v : move file to another circle
  • y : copy, add the (file . position) to another circle
  • j : join the files of two circles, a new circle is created to contain them
  • # : layout menu
    • m : manual mode, leave unchanged
    • o : only one window, delete the others
    • h : split horizontally to display all files of the circles
    • v : split vertically to display all files of the circles
    • g : split in a grid to display all files of the circles
  • o : reverse menu
    • l : reverse location order (file order) in a circle
    • c : reverse circle order in the torus
    • d : deep reverse : reverse both locations and circle
  • : : prefix circles names
  • ! : batch menu (be careful with this)
    • e : eval Elisp code on each file of the current circle
    • c : eval Elisp command on each file of the current circle
    • ! : eval Shell command on each file of the current circle
    • & : eval Async Shell command on each file of the current circle

Torus operations

You can create new toruses, beginning with a copy of the current torus, and switch easily between them. A list of toruses, called Meta Torus, is available. Some actions, like joining or autogrouping, also create new toruses.

  • + : add a new torus to the torus list (variable torus-meta)
  • * : add a new torus as a copy of the current torus
  • C-n : next torus
  • C-p : previous torus
  • @ : switch torus
  • S : search file in all toruses
  • N : rename torus
  • M-m : move torus in meta torus
  • V : move circle to another torus
  • Y : copy circle to another torus
  • J : join the circles of two toruses, a new torus is created to contain them
  • g : autogroup files in a new torus
    • p : group files by path
    • d : group files by directories
    • e : group files by extensions
  • - : delete a torus


I strongly suggest that you bind the functions you use most to quick shortcuts. Here are some examples :

(global-set-key (kbd "<S-s-insert>") 'torus-add-circle)
(global-set-key (kbd "<s-insert>") 'torus-add-location)

(global-set-key (kbd "<s-delete>") 'torus-delete-location)
(global-set-key (kbd "<S-s-delete>") 'torus-delete-circle)

(global-set-key (kbd "<C-prior>") 'torus-previous-location)
(global-set-key (kbd "<C-next>") 'torus-next-location)

(global-set-key (kbd "<C-home>") 'torus-previous-circle)
(global-set-key (kbd "<C-end>") 'torus-next-circle)

(global-set-key (kbd "s-SPC") 'torus-switch-circle)
(global-set-key (kbd "s-=") 'torus-switch-location)
(global-set-key (kbd "s-^") 'torus-switch-torus)

(global-set-key (kbd "s-*") 'torus-search)
(global-set-key (kbd "s-/") 'torus-search-history)

(global-set-key (kbd "<S-prior>") 'torus-history-newer)
(global-set-key (kbd "<S-next>") 'torus-history-older)

(global-set-key (kbd "C-^") 'torus-alternate-in-same-torus)

(global-set-key (kbd "<S-home>") 'torus-alternate-circles)
(global-set-key (kbd "<S-end>") 'torus-alternate-in-same-circle)


On the tab bar

If you set torus-display-tab-bar to t, a minimalist tab bar will take place on the top of your torus buffers. Appearence :

current-torus-name >> current-circle-name > current-location | location-2 | location-3 | ...

You can click on it to navigate :

  • Torus name region
    • Left click : switch torus with completion
    • Right click : meta search on all files of all toruses
    • Wheel : next / previous torus
  • Circle name region
    • Left click : switch circle with completion
    • Right click : search on all files of the current torus
    • Wheel : next / previous circle
  • Location region
    • Left click
      • Current location : alternate two last locations in same circle
      • Other locations : go to that location
    • Right click : switch location with completion
    • Wheel : next / previous location


Here is a sample configuration :

(require 'torus)

(setq torus-prefix-key "s-t")

;; Range 0 -> 3
;; The bigger it is, the more bindings.
(setq torus-binding-level 1)

;; Created if non existent
(setq torus-dirname "~/.emacs.d/torus/")

;; Set it to t if you want autoload of torus on Emacs startup
(setq torus-load-on-startup t)

;; Set it to t if you want autosave of torus on Emacs exit
(setq torus-save-on-exit t)

;; Where to auto load & save torus
(setq torus-autoread-file "~/.emacs.d/torus/last.el")
(setq torus-autowrite-file torus-autoread-file)

;; Number of backups you want
;; They will be numbered your-file.el.1 to your-file.el.N
(setq torus-backup-number 5)

(setq torus-history-maximum-elements 30)

(setq torus-maximum-horizontal-split 3)
(setq torus-maximum-vertical-split 4)

;; Format :
;; torus >> circle > [ file:line ] | file:line | file:line | ...
(setq torus-display-tab-bar t)




If you declare Torus with use-package and want the start/quit hooks to load/save your torus file, you’ll have to add a :hook section to the declaration :

(use-package torus
  :bind-keymap ("s-t" . torus-map)
  :bind (("<S-s-insert>" . torus-add-circle)
	   ("<s-insert>" . torus-add-location)
	   ("<s-delete>" . torus-delete-location)
	   ("<S-s-delete>" . torus-delete-circle)
	   ("<C-prior>" . torus-previous-location)
	   ("<C-next>" . torus-next-location)
	   ("<C-home>" . torus-previous-circle)
	   ("<C-end>" . torus-next-circle)
	   ("<S-prior>" . torus-history-newer)
	   ("<S-next>" . torus-history-older)
	   ("C-^" . torus-alternate-in-same-torus)
	   ("<S-home>" . torus-alternate-circles)
	   ("<S-end>" . torus-alternate-in-same-circle)
	   ("s-SPC" . torus-switch-circle)
	   ("s-=" . torus-switch-location)
	   ("s-^" . torus-switch-torus)
	   ("s-*" . torus-search)
	   ("s-/" . torus-search-history)
	   :map torus-map
	   ("t" . torus-copy-to-circle))
  :hook ((emacs-startup . torus-start)
	   (kill-emacs . torus-quit))
  :custom ((torus-prefix-key "s-t")
	     (torus-binding-level 3)
	     (torus-verbosity 1)
	     (torus-dirname (concat user-emacs-directory (file-name-as-directory "torus")))
	     (torus-load-on-startup t)
	     (torus-save-on-exit t)
	     (torus-autoread-file (concat torus-dirname "last.el"))
	     (torus-autowrite-file torus-autoread-file)
	     (torus-backup-number 5)
	     (torus-history-maximum-elements 30)
	     (torus-maximum-horizontal-split 3)
	     (torus-maximum-vertical-split 4)
	     (torus-display-tab-bar t)
	     (torus-separator-torus-circle " >> ")
	     (torus-separator-circle-location " > ")
	     (torus-prefix-separator "/")
	     (torus-join-separator " & "))


  • version 1.10
    • search in all toruses
    • previous and next torus
    • move torus
    • copy & move circle to torus
    • mouse support in tab bar
    • batch operations
  • version 1.9 : backup of torus files
  • version 1.8 : tab bar
  • version 1.7 : autogroups, layout
  • version 1.6 : join, ready for MELPA
  • version 1.2 - 1.5 : move, copy, reverse, history, split, alternate
  • version 1.1 : input history
  • version 1.0 : switch
  • before : lost in the mist of prehistory

Author & Licence

  • Copyright (C) 2019 Chimay
  • Licensed under GPL v2


Despite abundant testing, some bugs might remain, so be careful.

You can’t perform that action at this time.