Search code examples
emacselisp

How can I cycle through only those buffers which are in a given major mode (such as Python-mode ) ?


How can I cycle through only those buffers which are in a given major mode (such as Python-mode ) ?

Currently I am using C-X-Left/Right arrows, but these also show all sorts of irrelevant (i.e. non source code) buffers, any idea how can I restrict the buffer switching only to a specific type of buffer (with a given major mode) ?


Solution

  • I could not find something ready-made. However, it is not very hard to make the suitable commands.

    (defun buffer-mode-alist ()
      "Returns a list of (<buffer-name> . <major-mode>) pairs."
      (let ((all-buffers (buffer-list))
        (rv nil))
        (while all-buffers
          (let* ((this (car all-buffers))
             (name (buffer-name this)))
        (setq all-buffers (cdr all-buffers))
        (when name
          (setq rv (cons (cons name (with-current-buffer this major-mode)) rv)))))
        rv))
    
    (defun buffers-with-major-mode (the-major-mode)
      (let ((buffer-alist (buffer-mode-alist))
        (rv nil))
        (while buffer-alist
          (let ((this (car buffer-alist)))
        (setq buffer-alist (cdr buffer-alist))
        (if (eql (cdr this) the-major-mode)
            (setq rv (cons (car this) rv)))))
        (sort rv #'string<)))
    
    (defun spin-buffers (buffer-list current)
      (cond ((not (member current buffer-list)) buffer-list)
            ((string= current (car buffer-list)) buffer-list)
            (t (spin-buffers (append (cdr buffer-list)
                                     (list (car buffer-list)))
                             current))))
    
    (defvar next-buffer-mode nil)
    
    (defun choose-next-buffer-mode (mode)
      "Ask for what major mode should be used as a selector for next-buffer-with-mode."
      (interactive "aMajor Mode: ")
      (setq next-buffer-mode mode))
    
    (defun next-buffer-with-mode (set)
      "Switches to the 'next' buffer with a given mode. If the mode is not set,
    require it to be set, by calling choose-next-buffer-mode. If any prefix
    argument is passed, also call choose-next-buffer-mode."
      (interactive "P")
      (when (or (not next-buffer-mode)
            set)
        (call-interactively 'choose-next-buffer-mode))
      (let ((buffers (spin-buffers (buffers-with-major-mode next-buffer-mode)
                       (buffer-name))))
        (when (cdr buffers)
          (switch-to-buffer (cadr buffers)))))
    
    (defun prev-buffer-with-mode (set)
      "Switches to the 'previous' buffer with a given mode. If the mode is not set,
    require it to be set, by calling choose-next-buffer-mode. If any prefix
    argument is passed, also call choose-next-buffer-mode."
      (interactive "P")
      (when (or (not next-buffer-mode)
            set)
        (call-interactively 'choose-next-buffer-mode))
      (let ((buffers (spin-buffers (buffers-with-major-mode next-buffer-mode)
                       (buffer-name))))
        (when buffers
          (switch-to-buffer (car (last buffers))))))