0

Let's say I have the following contact in my org-contacts org file :

* John Doe     
  :PROPERTIES:
  :EMAIL:    john.doe@gmail.com
  :PHONE: +44 20 7630 2400
  :COMPANY: Ubuntu
  :NOTE: 
  :END:

How could I build a macro (I guess a function activated by a key binding) that would allow me to automatically create an org-store-links that would link to an orgmode file located in ~\myfolder based on the contact name, when I point the cursor after :NOTE:.

Here the generated link would be [[~\myohterfolder\johndoe.org][John Doe Card]]

Or maybe a function could be inserted in the org-capture-template to generate the link when the contact is created. Here is my template:

("c" "Networking Contacts" entry (file+headline "~/path/contacts.org" "Networking")
 "* %(org-contacts-template-name)
  :PROPERTIES:
  :EMAIL: %(org-contacts-template-email)
  :PHONE:
  :COMPANY: [[./otherpath/companies.org::][C]]
  :NOTE: 
  :END:")
1

If org-contacts-template-name returns the template name ("John Doe" in your example), then you should be able to do something like this:

   ...
   :NOTE: [[file:~/myotherfolder/%(munge (org-contacts-template-name)).org][%(org-contacts-template-name) Card]]
   ...

where munge is a function that takes the template name and returns the basename of the file ("johndoe" in your example), e.g. by converting it to lower case and deleting whitespace:

(defun munge (tname)
  (downcase (replace-regexp-in-string "[[:space:]]+" "" tname)))

Tested only in simulation: I don't have org-contacts installed.

EDIT: here's a quick and dirty way to get the name interactively once and then use it later for the other cases:

(defvar org-contacts-template-name nil)

(defun munge (tname)
  (downcase (replace-regexp-in-string "[[:space:]]+" "" tname)))

(defun my-org-contacts-template-name (&optional arg)
  (if arg
      arg
    (setq org-contacts-template-name (read-from-minibuffer "Name: " nil))))

(setq org-capture-templates
      '(("c" "Networking Contacts" entry (file+headline "~/tmp/org/contacts.org" "Networking")
 "* %(my-org-contacts-template-name)
  :PROPERTIES:
  :PHONE:
  :EMAIL: %(org-contacts-template-email)
  :COMPANY: [[file:~/tmp/org/companies.org::][C]]
  :NOTE: [[file:~/tmp/org/%(munge (my-org-contacts-template-name org-contacts-template-name)).org][%(my-org-contacts-template-name org-contacts-template-name) Card]]
  :END:")))

Basically, we define a (dynamically scoped, global) variable org-contacts-template-name, and we use a different function to ask the user to enter a value which is saved in that global variable. The function is called again, but now with a non-nil argument (the value of the previously-set global variable, which is just returned in that case) in the other instances of the template. This is probably quite delicate and fragile (e.g. it assumes that the capture template is processed top-to-bottom, which seems to be the case today, but there are no guarantees; there is also no error handling at all), but it does seem to work. Extending it to more inputs is left as an exercise. I would recommend the Introduction to Emacs Lisp: if you are going to hack Emacs Lisp, then you need to learn some :-)

15
  • Thanks for the try. Here is what it does when I do C-c cn: it asks me for the name, then for the email, then 2 times for the name. So in order to have the expected result, I have to type: John Doe ENTER; john.doe@gmail.com ENTER; johndoe ENTER, John Doe ENTER.
    – crocefisso
    2 days ago
  • That's why I qualified it with that first "If...": I didn't (and still don't) know how org-contacts-template-name works: it seems that it's interactive which is a pity: you want it to be stateful in this case. I'll see what I can do, but it would be better if somebody who actually uses org-contacts could chime in.
    – NickD
    2 days ago
  • I'm trying in vain to understand how I could code a function that would. 1. Ask me to type a value and store it as a string in a variable. So I could use the variable to populate the link (using (downcase (replace-regexp-in-string "[[:space:]]+" "" tname))`) and the link name. So the prompt would only ask me for : name, email, card name. I only know Python, and it's quite hard for me to find how to do such simple things on Elisp.
    – crocefisso
    2 days ago
  • 1
    That's activated only if you are using Gnus for your email and you are capturing from that email. Are you? If so, then there is no interactivity. But in general, that or has more arguments: (or (car (org-contacts-gnus-get-name-email)) return-value "%^{Name}")) so it returns the contact name from the email (if applicable) OR the argument to the function if non-nil OR the string %^{Name} which causes org-capture to interactively ask for a name. It's that latter case that you encountered in your first comment.
    – NickD
    2 days ago
  • 1
    The same way that I used read-from-minibuffer in my edit to the answer: you can replace the read-from-minibuffer call with read-string if you want. See the doc strings of the two functions for the differences: C-h f read-from-minibuffer etc.
    – NickD
    2 days ago
0

Thanks to @NickD inputs I found a satisfying solution. Here is the code:

Naming Org file

#+begin_src emacs-lisp
  (defun org-name (tname)
    (downcase (replace-regexp-in-string "[[:space:]]+" "" tname)))
#+end_src

Contact name input

#+begin_src emacs-lisp
  (defun con-input()
    (setq x (read-from-minibuffer "Card : ")))
#+end_src

Company name input

#+begin_src emacs-lisp
  (defun com-input()
    (setq y (read-from-minibuffer "Company : ")))
#+end_src

org-contacs capture

#+begin_src emacs-lisp 
  ("c" "Networking Contacts" entry (file+headline "...path/contacts.org" "Networking")
   "* %(org-contacts-template-name)
:PROPERTIES:
:EMAIL: %(org-contacts-template-email)
:PHONE:
:NOTE:  [[.../otherpath/%(org-name(con-input)).org][%(princ x) Card]]
:COMPANY: [[.../anotherpath/companies.org::%(com-input)][%(princ y)]]
:NOTE: 
:END:")
#+end_src
3
  • The output functions are unnecessary and confusing: you don't care about printing anything to an output stream. princ happens to return its argument (which is what you use here), but it is principally used to print something to an output stream (which you don't use here at all - that's why I think it's confusing). You also should not call the canned org-contacts-template-name since it will ask a question: the object of the game (I thought) was to ask as few questions as possible and then fill in the blanks with the answer or a somewhat massaged version of the answer.
    – NickD
    2 days ago
  • The goal (sorry if it wasn't clear enough in my question) was to automatically build an org-link from the org-contacts prompt. I thought at first it would be a good idea to use the package name function. But afterward, thought it would be easier not to.
    – crocefisso
    2 days ago
  • The code I wrote is providing me with the expected results. I don't really understand why princ is wrong, but if you have an alternative that would produce the same results, I'd be happy to edit my code with it.
    – crocefisso
    2 days ago

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.