0

I am setting a buffer-local variable called my/tab-order in (some) of my buffers.

I have written the following function to return a list of buffers only where my/tab-order has been set and is greater than 0.

  (defun my/unsorted-buffer-list ()
    (seq-filter (lambda (buf)
                  (and
                   (local-variable-p 'my/tab-order buf)
                   (> (buffer-local-value 'my/tab-order buf) 0))
                  )
                (buffer-list)))

I would now like a new function that sorts this list, according to my/tab-order (which is an integer).

I can sort this list by name with this function:

  (defun my/sorted-buffer-list ()
    (sort (mapcar #'buffer-name (my/unsorted-buffer-list)) #'string<)))

But I can't figure out how to sort by the buffer-local-variable. How can I do this?

1

IIUC, you want a function that will return the value of my/tab-order in a given buffer. Then you can use that function the same way (well, almost) that you use buffer-name to sort the buffers by name.

Since you are applying the function only to a list of buffers where my/tab-order is defined, we'll dispense with checking whether the value exists and what to do if it does not: we'll assume it's there.

The function is simple:

(defun my/buffer-tab-order (buffer)
   (with-buffer buffer
       (list my/tab-order (buffer-name buffer))))

The function returns a two-element list consisting of the tab order of the buffer and its name (since ultimately, the buffer name is what you want).

We need a comparison function that can compare two such lists and tell us which one is smaller. It just needs to compare the tab order of each such list which is the first element:

(defun my/buffer-tab-order< (l1 l2)
   (< (nth 0 l1) (nth 0 l2)))

Then we map it across the list of buffers of interest and sort the results, using our comparison function for the two-element list structure:

(defun my/sorted-buffer-list ()
  (sort (mapcar #'my/buffer-tab-order (my-unsorted-buffer-list)) #'my/buffer-tab-order<))

This produces the sorted list of (tab-order buffer-name) two-element lists. If you just want the buffer names only, just map a cadr on the list:

(defun my/sorted-buffer-list ()
  (mapcar #'cadr 
     (sort (mapcar #'my/buffer-tab-order (my-unsorted-buffer-list)) #'my/buffer-tab-order<)))

Untested. It should work modulo typos: let me know if you run into problems.

The idea of attaching a sort key to an object, sort by the key value and then strip the sort keys out, is a common (almost ubiquitous) one. Here's an example from "The AWK Programming Language" from 1988, but it certainly goes back much further.

1
  • Works a charm, and the explanation really helped. Thanks so much. :)
    – randouser
    Oct 28 '21 at 22:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.