5

So I'm looking for some insight into how to customize my ibuffer window. I don't know much lisp but have a decent amount of emacs experience.

I tried solving it based on some google searches:
http://emacswiki.org/emacs/IbufferMode#toc10
http://www.emacswiki.org/emacs/DiredMode
and a few more links. I've tried various combinations of the tools they describe, but nothing does exactly what I want, which is roughly a combination of sorting by pathname, and filter groups. However, instead of predefined 'saved-filter-groups', I want to have filter groups based on the directory structure.

Ideally my ibuffer would display directory names as filter groups, and then sort the files alphabetically within each group. Also if possible, I would like the named directory filter groups to only display up to 3 parent directory levels

So if the buffers I have open are:

~/SomeDir/Foo/Bar/a/file_1a.js
~/SomeDir/Foo/Bar/a/file_2a.js
~/SomeDir/Foo/Bar/b/file_1b.js
~/SomeDir/Foo/Bar/b/file_2b.js

Then my ibuffer window would look like:

[ .../Foo/Bar/a ]
  file_1a.js
  file_2a.js
[ .../Foo/Bar/b ]
  file_1b.js
  file_2b.js

While I'd love a complete solution, any insight or resources you could point me towards would be nice too.

1

Here's a solution offered by puercopop that I've been using, which works pretty well. I've modified it slightly in the following rehash (reproduced here to sidestep possible link rot):

;; create a "default" placeholder to build the filter groups
(setf ibuffer-saved-filter-groups (quote (("default"))))

;; replace the PROJECTS directory with whatever you like
(cl-dolist (dir (directory-files "~/projects/"))
  (when (not (member dir '("." "..")))
    (setf (car ibuffer-saved-filter-groups)
          (append (car ibuffer-saved-filter-groups)
                  `((,dir
                     (filename . ,(expand-file-name
                                   dir "~/projects/"))))))))
0

Here are some hints: First you need to write a filter, which will match members of one of the desired groups, i.e. by directory-name.

(define-ibuffer-filter directory-name
    "Filter by directory-name `equal'ity."
  ...)

Then you need to write some function, which will setup ibuffer-filter-groups like this:

(setq ibuffer-filter-groups
      (("abbrev-dir1" (directory-name . "dir1"))
       ("abbrev-dir2" (directory-name . "dir2"))
       ....))

, where dir1, dir2, etc. are the directories occuring in the ibuffer buffer (see e.g. ibuffer-map-lines). Finally use ibuffer-update to display the groups.

0

Not really part of the question, but here's a sorter that sorts by directory.

  (define-ibuffer-sorter pathname
    "Sort by pathname"
    (:description "path")
    (cl-flet ((get-pathname
               (data)
               (with-current-buffer (car data)
                 (or buffer-file-name
                    (if (eq major-mode 'dired-mode)
                        (expand-file-name dired-directory))
                    ;; so that all non pathnames are at the end
                    ""))))
      (string< (get-pathname a) (get-pathname b))))

  (define-key ibuffer-mode-map
    (kbd "s p") 'ibuffer-do-sort-by-pathname)

This defines a directory filter:

  (defun get-all-buffer-directories ()
    "Return a list of all directories that have at least one
       file being visited."
    (interactive)
    (let (l)
      (dolist (e (sort (mapcar 'file-name-directory
                               (remove-if-not 'identity
                                              (mapcar 'buffer-file-name
                                                      (buffer-list))))
                       'string<))
        (unless (string= (car l) e)
          (setq l (cons e l))))
      l))

  (define-ibuffer-filter dirname
      "Toggle current view to buffers with in a directory DIRNAME."
    (:description "directory name"
                  :reader
                  (intern
                   (completing-read "Filter by directory: "
                                    (get-all-buffer-directories)
                                    'identity
                                    t nil nil nil nil)))
    (string= qualifier
             (and (buffer-file-name buf)
                (file-name-directory (buffer-file-name buf)))))

This uses the filter to create filter groups by directory:

  (defun ibuffer-set-filter-groups-by-directory ()
    "Set the current filter groups to filter by directory."
    (interactive)
    (setq ibuffer-filter-groups
          (mapcar (lambda (dir)
                    (cons (format "%s" dir) `((dirname . ,dir))))
                  (get-all-buffer-directories)))
    (ibuffer-update nil t))

  (define-key ibuffer-mode-map
    (kbd "/ D") 'ibuffer-set-filter-groups-by-directory)
  (define-key ibuffer-mode-map
    (kbd "/ d") 'ibuffer-filter-by-dirname)

You could modify the format expression to truncate the filter group names.

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.