Home | | Help | Contribute | Plug-ins | About | Contact | Search
Shortcut to cycle open buffers
Team | Miguel's home

February, 2015

Note. It is best to read the original TeXmacs file with interactive Scheme sessions where one may experiment with the code. It can be found in the project's source code, inside the directory web/miguel.


It would be a much appreciated feature to have a keyboard shortcut to cycle through all open buffers in a TeXmacs session. Of course, there is the Go menu, but is there ever a mouse to be found when you need one? We provide this much sought after feature.


Well, we would very much like it. And at least one of us wants to learn how to improve his coding skills and get to know TeXmacs. So here it is. (Because we can is another valid motivation).


Warning. First things first: you will need a working source installation of TeXmacs, meaning you will need to compile the sources to test these things out. Unless you already have TeXmacs version 1.99.3 or an svn revision greater than 89??, which will most likely include / includes these features.

We proceed in five steps:

  1. Add the information on when buffers were opened to the internal data structure representing them.

  2. Implement a C++ function to return this value for any given buffer (by url).

  3. Export (a.k.a. “glue”) this function to the Scheme interpreter.

  4. Actually implement the feature “go to next/previous buffer”.

  5. Add shortcuts

    To do: and menu items
    to use this feature.

A bit of plumbing (steps 1-2)

Note. Indications of line numbers are based on an svn revision around 8840. If you have any other version of the sources there might be differences.

We first need to add a routine to TeXmacs which returns the time at which a buffer was opened. This is going to be the default ordering of the buffers in our swapping list and serves the purpose of consistently sorting it regardless of recent activity, as opposed to what is currently done in the Go menu.

First we need to save this information. In the file src/Texmacs/Data/new_buffer.hpp add the following (~line 31):

time_t open_time;       // time that the buffer was opened

We want that the timestamp is added (as metadata) to the buffer when the buffer is created so we need to modify the last line of the constructor inline new_buffer_rep (url name2) to read:

last_visit (texmacs_time ()), open_time (texmacs_time()) {}

We now add the declaration of the method which will return the data we just initialized. Define (~line 90):

double buffer_open_time (url name);

This function is made mimicking buffer_last_visit and will be the one which the scheme interpreter calls when the scheme command buffer-open-time is called. In the file src/Texmacs/Data/new_buffer.cpp add the following (~line 350):

buffer_open_time (url name) {
    tm_buffer buf= concrete_buffer (name);
    if (is_nil (buf)) return (double) 0;
    return (double) buf->buf->open_time;

All these files and places within files were found by searching for occurrences of last_visited.

The following part is some auto-magic: we use a script to export our C++ code for the Scheme interpreter.

Gluing it (step 3)

Now that we have the infrastructure, we may add it to the “glue”, that is, we export it to the Scheme interpreter. In the file src/Scheme/Glue/build-glue-basic.scm add the following (~line 565, where buffer-last-visited is declared):

(buffer-open-time buffer_open_time (double url))

Now go to src/Scheme/Glue and do the following:

./build-glue build-glue-basic.scm glue_basic.cpp

Scheme implementation (steps 4-5)

For this section we will be looking for inspiration in file-menu.scm, which we found investigating how the menu Go is created and modified.

The first thing we need is to be able to order the buffers from the oldest to the newest, hence we start with the routine ordering them.


(define (buffer-first-opened? b1 b2)

(>= (buffer-open-time b1)

(buffer-open-time b2)))

Here we used the routine buffer-open-time which we just exported via the glue. Now we want to actually sort the list of open buffers which is the same used in the Go menu, but without truncating it to a fixed number and sorting it with the previous routine. We do this with the following function.


(define (buffer-sorted-list)

(with l (list-filter (buffer-list) buffer-in-menu?)

(list-sort l buffer-first-opened?)))

Now we have to cycle through the list looking for our buffer (the current one) and returning the next one. We will create an auxiliary function find-next* with an extra parameter to hold the first item of the list, but we will actually be using find-next.


(define (find-next* l first what)

(cond ((null? l) first)

((== what (car l)) (if (nnull? (cdr l)) (cadr l) first))

(else (find-next* (cdr l) first what))))


(define (find-next l what)

(if (null? l) "" (find-next* l (car l) what)))

Now, if we want to move forwards then we cycle the list of current buffers starting from the current one, otherwise we revert the list and we cycle in the same way. Do not forget the last line, telling the function what to do with the buffer it gets.


(define (buffer-cycle forwards?)

(with b (current-buffer)

(with next

(if forwards?

(find-next (buffer-sorted-list) b)

(find-next (reverse (buffer-sorted-list)) b))

(switch-to-buffer next))))


(buffer-cycle #f)

Finally we actually define the shortcuts.



("M-A-left" (buffer-cycle #f))

("M-A-right" (buffer-cycle #t)))

Note. If you want to extract the code from this document, activate ToolsDeveloper tools and with the cursor inside a session click on DeveloperExport sessions…

This webpage is part of GNU TeXmacs and the larger GNU project. Verbatim copying and distribution of it is permitted in any medium, provided this notice is preserved. For more information or questions, please contact Joris van der Hoeven.

Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA