1

I am trying to write functions that insert entries, or link to entries of my contacts org-mode file using org-contacts.

The functions would work as follows:

  • First prompt for a contact name (maybe using the org-contacts command).
  • On pressing l, insert a link to the selected contact where point was in the original buffer, then quit the temporary contacts buffer.
  • On pressing c, insert a copy of the subtree corresponding to the selected contact and exit the temporary buffer.

I think the following commands may come in handy: org-contact, org-store-link, org-agenda-quit. I am working on it right now but my lisp skills are very limited. Any idea about how to proceed would be very welcome.

Linking could be made more robust by using a setup similare to these:

but this is probably even more complex.

2
  • Could you tell me why you are not happy with my answer below? Maybe, I can fix that issue.
    – Tobias
    May 18, 2015 at 13:36
  • @Tobias, I have yet to read it and try it. It looks great.
    – M. Toya
    May 18, 2015 at 16:00

1 Answer 1

3

One way to accomplish what you want is to wrap org-contacts with a special org-contacts-mode as demonstrated in the following. This new major mode defines the keys l and c as you specified it in its local keymap.

You may paste the code into your .emacs file after (require 'org-contacts) or a suitable autoload.

You can just call org-contacts instead of your proposed new function. Put point at the entry you want to insert into the original buffer and press l or c.

(require 'org-contacts)

(define-derived-mode org-contacts-mode org-agenda-mode "org-contacts"
  "Like `org-agenda-mode' with the following alternative key-bindings:
l: insert a link to the selected contact at point in the original buffer
c: insert a copy of the subtree corresponding to the contact at point in the original buffer
Both commands burry the contacts buffer afterwards.
")

(defadvice org-contacts (around contacts-mode activate)
  "Wrap `org-contacts' with `org-contacts-mode' where special keybindings are in effect.
See `org-contacts-mode' for further details."
  (let* ((org-contacts-buffer (get-buffer-create "*org-contacts*"))
     (original-buffer (current-buffer))
     (org-agenda-buffer-name (buffer-name org-contacts-buffer)))
    (switch-to-buffer org-contacts-buffer)
    ad-do-it
    (org-contacts-mode)
    (setq-local org-contacts-original-buffer original-buffer)))

(defun org-contacts-return (content)
  "Insert CONTENT into original buffer and switch there."
  (declare (special org-contacts-original-buffer))
  (unless (and
       (boundp 'org-contacts-original-buffer)
       org-contacts-original-buffer)
    (error "Cannot determine the original buffer.
Note, you should not manually activate `org-contacts-mode'."))
  (let ((original-buffer org-contacts-original-buffer))
   (bury-buffer)
   (switch-to-buffer original-buffer)
   (insert content)))

(defun org-subtree-string (&optional marker)
  "Return subtree at location MARKER.
MARKER should be nil or a marker pointing to a live org-buffer.
If MARKER is nil it corresponds to the current point in the current buffer."
  (let ((buf (or (and (markerp marker) (marker-buffer marker)) (current-buffer)))
    (pt (or (and (markerp marker) (marker-position marker)) (point)))
    b e)
    (with-current-buffer buf
      (unless (derived-mode-p 'org-mode)
    (error "This is not an org-mode buffer."))
      (save-excursion
    (goto-char pt)
    (org-back-to-heading t)
    (setq b (point))
    (org-end-of-subtree t)
    (setq e (point)))
      (buffer-substring b e))))

(setq org-contacts-mode-map (let ((map (make-sparse-keymap)))
                  (define-key map [?l]
                (lambda () (interactive)
                  (let* ((marker (org-get-at-bol 'org-hd-marker))
                     (buf (marker-buffer marker))
                     (filename (expand-file-name (buffer-file-name buf))))
                    (org-contacts-return
                     (concat "[[file:" filename "::"
                         (nth 4 (org-with-point-at marker
                              (org-heading-components)))
                         "]]")))))
                  (define-key map [?c]
                (lambda () (interactive)
                  (let* ((marker (org-get-at-bol 'org-hd-marker)))
                    (org-contacts-return
                     (org-subtree-string marker)))))
                  map))

Usage-Example: Assume you have already defined some contact with name Nobody and you want to insert a copy of the contact in file test.org at the current point position.

  1. With point at the place where you want to insert the copy of the contact call M-x org-contacts. Maybe, you have already a key-sequence for that. You get the prompt for the contact name from org-contacts as shown in the following figure.

    org-contacts call

  2. Input the contact name ("Nobody" in our example). You get an org-contacts buffer with all matches of "Nobody". In our example there is just one match. Place point on the match of your like.

    org-contacts buffer

  3. For copying the corresponding contact into the target buffer press c (see following figure).

    Copy of the contact

  4. If you press l instead of c you get a link to the contact as shown in the following figure below the copied contact. (Note, that I have replaced some sensitive data by three dots. Actually, you get the absolute path to the contact file.)

    Link to contact

1
  • This looks fabulous. Do you think there is a way to list all the TODOs linked too Nobody? Oct 19, 2019 at 21:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.