Skip to content

gunther-bachmann/emacs-dired-annotator

Repository files navigation

dired-annotator

Keep notes to files in dired.

General ideas

This package will either use hashes or absolute file names to associate org notes with regular files. Whereas hashes will enable to identify files that may have been moved but did not change, the absolute file name will identify files that changed but did not move.

When adding a note to a file, the identification method (hash or absolute file name) is selected. Currently there is no way to change this easily afterwards.

All notes are kept as org files within a single folder.

It is integrated with dired. Files that have associated note files will be annotated in dired (e.g. with a document symbol). This can be switched on and off. The note can be viewed (e.g. with a posframe) opening the note.

Since getting the hash of folders with a large number of files takes some time, default is that nothing is displayed. Switching it on, all file hashes are computed and each file is checked whether a note is available for that file. Those files with associated note files will be marked with the configured icon.

It also is integrated with dired-subtree (repo). When unfolding trees while notes should be displayed, all additional files displayed will be checked. Folding will then remove those icons alongside the subtree.

The integration with dired-sidebar (repo) is somewhat limited, since tracking changes in the sidebar will toggle reruns of the hashing of the whole folder (and open subfolders) which might take a while. This cannot be prevented at the moment.

Installation

Since this currently is no package available on gnu, non-gnu nor melpa, clone the repository

git clone https://github.com/gunther-bachmann/emacs-dired-annotator

and add this to your init file. Please adjust the load-path to the folder into which the project was cloned and please make sure configure a folder ( dired-annotator-annotations-folder) where the actual annotation files are stored.

(use-package dired-annotator
  :load-path "~/repo/emacs-dired-annotator"
  :custom (dired-annotator-annotations-folder (expand-file-name "~"))
  :bind (:map dired-mode-map
              ("C-c a s" . #'dired-annotator-show-icons)
              ("C-c a h" . #'dired-annotator-hide-icons)
              ("C-c a k" . #'dired-annotator-delete-note)
              ("C-c a o" . #'dired-annotator-edit-note)
              ("C-c a e" . #'dired-annotator-edit-note)
              ("C-c a a" . #'dired-annotator-show-note)
              ("'" . #'dired-annotator-show-note)))

A more complex example configuration using all-the-icons (repo), posframe (repo), dired-narrow (repo) and org-ql (repo). Please make sure to

  • adjust load-path to the location where dired-annotator is checked out to
  • adjust dired-annotator-annotations-folder to point to an existing folder
(use-package dired-annotator
  :after (posframe all-the-icons org-ql dired-narrow)
  :load-path "~/repo/emacs-dired-annotator"
  :custom ((dired-annotator-note-icon (all-the-icons-faicon "sticky-note"))
           (dired-annotator-annotations-folder (expand-file-name "~/documents/annotations"))
           (dired-annotator-note-popup-hook #'dired-annotator--posframe-note-popup)
           (dired-annotator-note-fill-column 54) ;; a bit smaller than the popup window
           (dired-annotator-note-popup-remove-hook '(dired-annotator-register-buffer-cleanup
                                                     dired-annotator--remove-all-posframes)))
  :hook (dired-mode . dired-annotator-check-dir-local-show)
  :init
  (require 'posframe)
  (defconst dired-annotator-note-popup-width 56 "width of the note that pops up")
  (defconst dired-annotator-note-popup-height 40 "max height of the note that pops up")

  (defun dired-annotator--remove-all-posframes ()
    "remove all posframes"
    (unless (eq 'dired-annotator-show-note (lookup-key dired-mode-map (this-single-command-keys)))
      (setq dired-annotator--note-should-not-popup nil))
    (ignore-errors
      (posframe-hide-all)))

  (defun dired-annotator--posframe-note-popup (position annotation-file)
    (setq dired-annotator--note-should-not-popup t)
    (let ((note-buffer (find-file-noselect annotation-file)))
      (with-current-buffer note-buffer
        ;; make sure that regardless of org startup visibility, the buffer is fully visible
        (org-show-all))
      (posframe-show note-buffer :position position :lines-truncate t
                     :width dired-annotator-note-popup-width
                     :border-color "plum4" :border-width 2 :left-fringe 3 :right-fringe 3 )))

  :bind (:map dired-mode-map
              ("C-c a r" . #'dired-annotator-reload-annotation-info)
              ("C-c a d" . #'dired-annotator-dired-on-annotation-folder)
              ("C-c a s" . #'dired-annotator-show-icons)
              ("C-c a h" . #'dired-annotator-hide-icons)
              ("C-c a k" . #'dired-annotator-delete-note)
              ("C-c a o" . #'dired-annotator-edit-note)
              ("C-c a e" . #'dired-annotator-edit-note)
              ("C-c a a" . #'dired-annotator-show-note)
              ("C-c a /" . #'dired-annotator-narrow-on-tag)
              ("'" . #'dired-annotator-show-note)))

Feel free to use different keybindings and customizations (see M-x customize-group for dired-annotator).

To automatically show the notes icons in a dired folder, add the following to your .dir-locals.el in that folder:

((dired-mode . ((dired-annotator-show . t))))

and configure to run dired-annotator-check-dir-local-show when entering dired-mode (see hook configuration).

Make sure to have required packages installed. Currently these are:

  • simple (built in)
  • uuid (repo)
  • dired (built in)
  • dash (repo)

Basic use cases

  • annotate a file that won’t change (e.g. media data like movies, music, pictures)
    • in the dired buffer navigate the cursor to the file
    • M-x dired-annotator-edit-note (or C-C a e)
    • select to type of reference (e.g. immutable-file)
    • edit the opened buffer (don’t edit the generated #+property line)
    • save and close the buffer

    now the dired buffer should show a mark to indicate that this file is annotated

  • view the annotation of a file
    • in a dired buffer navigate the cursor to an annotated file
    • M-x dired-annotator-show-note (or ')

    a popup with the note is shown that will be closed after any key is hit

Screen shots

dired buffer with some notes

screenshots/dired-annotator.dired-with-note.png

dired buffer with note popup

screenshots/dired-annotator.popup-note.png

integration with dired subtree

screenshots/dired-annotator.subtree.png

integration with dired sidebar

screenshots/dired-annotator.sidebar.png

create note

screenshots/dired-annotator.create.png

update note

screenshots/dired-annotator.create2.png

delete note

screenshots/dired-annotator.delete.png

Reporting issues

In order to undestand issues better it might be helpful to provide a report generated by dired-annotator-collect-report-data (excute this function in a dired buffer you use dired-annotator in). Even though the report should make sure to hide information behind hashes, please make sure that the report does not contain any personal information! It could also be helpful to configure dired-annotator to do logging by (setq dired-annotator-log-level 5) or add :custom (dired-annotator-log-level 5) to your use-package configuration and copy the relevant messages from the message buffer *Messages*.

Open issues/todos

  • TODO: fix native compilation warnings (for integrating with optional packates)
  • idea: how to change pinning mode for files ?
  • TODO: provide function to copy annotation file name into kill ring
  • idea: provide function to dired into annotation dir with point at current note
  • TODO: add testing
  • TODO: prevent hashing reruns in dired sidebar (because of tracking refreshes)
  • TODO: cleanup notes in subdirectories (e.g. when deleting subdirectories)
  • TODO: garbage collect dangling notes (probably only feasable for file name fixed notes)