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.

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

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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