9

I am using org-mode and org-attach extensively which means that there can be many attachment directories associated with one org file.

On worg I found a function from Matt Lundi which allows to see all attachments that belong to the whole file and browse them with ido.

I would like to restrict this function to a subtree which would make it much more useful for my use case.

Since I am not new to emacs but almost completely elisp illiterate I am asking here.

This is the function:

(defun my-ido-find-org-attach ()
  "Find files in org-attachment directory"
  (interactive)
  (let* ((enable-recursive-minibuffers t)
         (files (find-lisp-find-files org-attach-directory "."))
         (file-assoc-list
          (mapcar (lambda (x)
                    (cons (file-name-nondirectory x)
                          x))
                  files))
         (filename-list
          (remove-duplicates (mapcar #'car file-assoc-list)
                             :test #'string=))
         (filename (ido-completing-read "Org attachments: " filename-list nil t))
         (longname (cdr (assoc filename file-assoc-list))))
    (ido-set-current-directory
     (if (file-directory-p longname)
         longname
       (file-name-directory longname)))
    (setq ido-exit 'refresh
          ido-text-init ido-text
          ido-rotate-temp t)
    (exit-minibuffer)))
aculich
  • 14,545
  • 9
  • 64
  • 71

2 Answers2

3

Maybe I'm missing something, but calling org-narrow-to-subtree first should do what you want (call widen afterwards to revert that).

aculich
  • 14,545
  • 9
  • 64
  • 71
pokita
  • 1,241
  • 10
  • 12
  • The way `my-ido-find-org-attach` is written `org-narrow-to-subtree` has no effect since it blindly uses the value of `org-attach-directory`. – aculich Dec 23 '12 at 06:35
1

I thought this would be pretty darned useful myself so, inspired by your question, I wrote a version that does what you want plus a couple other bells and whistles. To invoke it you have to type C-c o. NOTE: This is NOT on the usual org-attach key prefix because that function is oddly written without a keymap so it is difficult to add the functionality onto the key prefix.

(autoload 'org-attach-dir "org-attach")
(autoload 'find-lisp-find-files "find-lisp")
(defcustom ido-locate-org-attach-all-files nil
  "Non-nil means `ido-locate-org-attach' returns all files.
Otherwise the default behavior only returns files attached to the
current entry."
  :group 'ido
  :type 'boolean)

(defun ido-locate-org-attach (&optional find-all)
  "Find files in org-attachment directory for current entry.
When called with a prefix argument, include all files in
`org-attach-directory'. With a double `C-u' prefix arg the value
of `ido-locate-org-attach-all-files' will be toggled for the
session. If you want to save it permanently for future session
then customize the variable `ido-locate-org-attach-all-files'."
  (interactive "P")
  (when (org-attach-dir nil)
    (when (equal find-all '(16))
      (setq ido-locate-org-attach-all-files
        (not ido-locate-org-attach-all-files)))
    (let* ((enable-recursive-minibuffers t)
       (dir (if (org-xor ido-locate-org-attach-all-files
                 (equal find-all '(4)))
            org-attach-directory
          (org-attach-dir nil)))
       (files (find-lisp-find-files dir "."))
       (file-assoc-list
        (mapcar (lambda (x)
              (cons (file-name-nondirectory x)
                x))
            files))
       (filename-list
        (remove-duplicates (mapcar #'car file-assoc-list)
                   :test #'string=))
       (filename (ido-completing-read "Org attachments: " filename-list nil t))
       (longname (cdr (assoc filename file-assoc-list))))
      (ido-set-current-directory
       (if (file-directory-p longname)
       longname
     (file-name-directory longname)))
      (setq ido-exit 'refresh
        ido-text-init ido-text
        ido-rotate-temp t)
      (exit-minibuffer))))

;; Run ido-locate-org-attach when using org-open-at-point (C-c C-o) in
;; the current entry (except if you're on the header line itself it
;; will use the default behavior to open/close the entry.
(add-hook 'org-open-at-point-functions 'ido-locate-org-attach)

;; C-c o           will locate files for the current entry
;; C-u C-c o       will locate files for the whole file
;; C-u C-u C-c o   will toggle the default current entry / whole file
(define-key org-mode-map "\C-co" 'ido-locate-org-attach)

I'll look into submitting this to be an official part of org-attach.el.

As an aside, the '(4) and '(16) are magic numbers that mean prefix arg once C-u and prefix arg twice C-u C-u before the key sequence that invoked the command interactively.

aculich
  • 14,545
  • 9
  • 64
  • 71
  • Thanks for this and sorry for the late reply. But unfortunately I cannot get your to work. When I am on a heading with an attachment directory it does the same as org-attach and o (Open current task's attachments.). When invoked on a parent heading nothing happens, when I would have expected to find all the attachment of the child headings. I must say that I am on windows but I don't think it relates since org-attach works flawlessly. – Otto Pichlhoefer Dec 28 '12 at 17:32
  • Try invoking it with `M-x ido-locate-org-attach` to make sure the function works. Are you invoking it with `C-c o` instead of using the org-attach key combo of `C-c C-a o`? I am not overriding the default keys for org-attach-open-in-emacs, just adding a different key binding outside of the org-attach prefix. – aculich Dec 28 '12 at 19:01
  • I already did this. both `C-C o` and `M-x ido-locate-org-attach` give the same result. BTW I am in Emacs 24.2.1 and org version 7.9.2 (from ELPA) – Otto Pichlhoefer Dec 28 '12 at 20:47
  • Can you create a gist with your *.org file content and an example attachment directory so I can try to recreate what you're seeing? I am also using Org-mode version 7.9.2 (from ELPA), but using GNU Emacs 24.1.1. – aculich Dec 28 '12 at 21:50