Support for imenu in dired
Date | Change |
---|---|
2018-09-22 | Use imenu--generic-function as part of custom index-making functions to capture indices generated by external packages |
imenu
is a very simple package that builds index of interesting
positions in the current buffer and presents them as a menu. You pick
the item and the point moves there. There is a built-in interface and
also one in sallet, helm or counsel.
Unfortunatelly dired
doesn't come with support for it, so here I add
some definitions to generate the index of all the inserted
directories.
The most common way to add items to the index is by modifying
imenu-generic-expression
which is a list of lists of the form
(GROUP-NAME REGEX MATCH-GROUP)
. Then imenu searches for the REGEX
and
adds the corresponding MATCH-GROUP
and its match position to the
index. This is done by imenu-default-create-index-function
which is
the default value of imenu-create-index-function
.
Another more generic way is to write your own functions
imenu-prev-index-position-function
and
imenu-extract-index-name-function
which find the position and the name
of the item. If both of these are set
imenu-default-create-index-function
uses those instead of the regexp
list.
I have a hybrid approach here. I use the regexp mechanism because
that is what most external packages use and I want to be able to
install those additions and use them seamlessly (for example
dired-hacks and its filter groups). But I also want to add some other
items to the index, so I set my own imenu-create-index-function
and
add some more items "manually".
In particular, I like to add all the parents of the current directory
which can then be opened via dired-open's dired-open-subdir
.
(defun my-dired-imenu-create-parents-index () "Create index of all parent positions of current dired." (save-excursion (dired-prev-subdir 0) (let (parents (beg (save-excursion (beginning-of-line) (1- (search-forward "/"))))) (while (search-backward "/" beg t) (push (cons (buffer-substring-no-properties beg (point)) (1- (point))) parents)) (cons "Parents" (cdr parents))))) (defun my-dired-imenu-create-index () "Create `imenu' index for dired." (let (subdirs-alist (parents-alist (my-dired-imenu-create-parents-index))) (let* ((imenu-generic-expression '(("Subdir" "^ \\(.*?\\):$" 1))) (alist (car (imenu-default-create-index-function))) (uniquified (f-uniquify-alist (-map 'car (cdr alist))))) (setq subdirs-alist (cons (car alist) (--remove (= 0 (length (car it))) (--map (cons (cdr (assoc (car it) uniquified)) (cdr it)) (cdr alist)))))) (let ((alist (imenu-default-create-index-function))) (-cons* subdirs-alist parents-alist alist)))) (defun my-dired-imenu-init () "Initialize `imenu' variables in current buffer." (setq-local imenu-create-index-function 'my-dired-imenu-create-index))
To use this just add my-dired-imenu-init
to dired-mode-hook
.
(add-hook 'dired-mode-hook 'my-dired-imenu-init)
The code depends on f
and dash
.