It is /predictable/ as it makes use of existing emacs functionality to display files in a tabulated way similar to the package menu. It is /composable/, integrating well with other emacs packages (denote, in this case) and builtin functionality, opting to not reinvent the wheel as to how the data is displayed. The scope of this package is narrow: displaying and filtering denote files in a visually appealing and intuitive manner. =denote-menu= is also /flexible/ and /hackable/, providing a simple API to create your own filters, and integrates well with dired by providing the =denote-menu-export-to-dired= command, which allows for further action on denote files beyond just viewing and filtering them.
[[file:screenshots/screenshot.png]]
M-x package-install RET denote-menu RET
This package requires Denote =v2.0.0= or above.
The tabulated list includes 3 columns, one for the timestamp, title, and keywords of each denote file. The timestamp column includes a button that when followed will open the corresponding denote file using =find-file=.
Filtering by regular expression To filter the denote files shown by a regular expression, run =M-x denote-menu-filter=. This will prompt for a regular expression and will update the buffer to list only those denote files whose filenames match. Running =denote-menu-filter= again will further filter down the list. This is akin to running =% m= inside a =dired= buffer. Filtering by keyword To filter the denote files shown to those that are tagged with specific keywords, run =M-x denote-menu-filter-by-keyword=. This command will prompt for a list of comma separated keywords (with completion) and filter the list to those denote files that are tagged with at least one of the inputted keywords. To filter /out/ any denote files by keyword, run =M-x denote-menu-filter-out-keyword=. ** Defining your own filters There are two ways to define your own filters:
Write an interactive function that sets =denote-menu-current-regex= to be a regular expression that matches your desired set of denote files, and then calls =denote-menu-update-entries=. For example, if I would like to a filter that filters out those denote files that were not tagged with the "biblio" keyword, I would add the following to my emacs configuration:
(defun my/denote-menu-filter-biblio-only () (interactive) (setq denote-menu-current-regex "_biblio") (denote-menu-update-entries))
Write an interactive function that sets =tabulated-list-entries= to a be a function that maps each desired denote file path to an entry using =denote-menu--path-to-entry= function, and calls =revert-buffer=. For example, if the variable =my-matching-denote-paths= contains a list of file paths of the desired denote files, then your filter function would look something like the following:
(defun my/denote-menu-filter-custom () (interactive) (let ((my-matching-denote-paths '("/home/namilus/zettelkasten/20220719T135304--this-is-my-first-note__meta.org"))) (setq tabulated-list-entries (lambda () (mapcar #'denote-menu--path-to-entry my-matching-denote-paths))) (revert-buffer)))
Clearing filters To clear the filters and revert back to the =denote-menu-initial-regex=, run =M-x denote-menu-clear-filters=. Exporting to =dired= Adhering to the tenets of predictability and composability, =denote-menu= provides the command =denote-menu-export-to-dired= to allow further action on these files that is permitted in dired e.g copying, moving, compressing, etc. We do not reinvent the wheel here but instead defer to what already exists.
When in the =Denote= buffer running =M-x denote-menu-export-to-dired= will open a =dired= buffer in the same window with those denote files that were displayed in the =Denote= buffer already marked.
A sample user configuration is given below that sets appropriate keybindings for the commands described in the previous section:
(require 'denote-menu)
(global-set-key (kbd "C-c z") #'list-denotes)
(define-key denote-menu-mode-map (kbd "c") #'denote-menu-clear-filters) (define-key denote-menu-mode-map (kbd "/ r") #'denote-menu-filter) (define-key denote-menu-mode-map (kbd "/ k") #'denote-menu-filter-by-keyword) (define-key denote-menu-mode-map (kbd "/ o") #'denote-menu-filter-out-keyword) (define-key denote-menu-mode-map (kbd "e") #'denote-menu-export-to-dired)