A dynamic snippet for a task due 7 days from now

| categories: emacs, org-mode | tags:

I have been playing with yasnippets. A pretty cool feature is that you can run elisp code in the template to generate text. Below, I define a snippet that will create a todo item due 7 days from the time you define it. This is an unconventional way to define a snippet, but I did not want to save it to a file just to try it out. So, I put it in a temporary buffer, and load it from there. When you run this block, it will note it is a new snippet, and ask if you want to save it. You can say no.

We will use the code we developed here to create a timestamp from the current time plus seven days.

(yas-global-mode)
(with-temp-buffer
  (insert "# name : todo-followup
# --

*************** TODO $1
${2:             DEADLINE: `(let ((seven-days (seconds-to-time (* 7 24 60 60))))
  (format-time-string \"<%Y-%m-%d %a>\" (time-add (current-time) seven-days)))`}$0
*************** END 
")
  (yas-load-snippet-buffer-and-close 'org-mode))

Now, you will have a new entry in the YASnippet menu that is called todo-followup. If you put the cursor on a blank line, and select that entry you get this below (after you fill in the text for the headline, of course!):

*************** TODO see how many times this was viewed
		DEADLINE: <2014-02-23 Sun>
*************** END

That is pretty nice, as it saves a lot of keystrokes for that particular kind of task. Let us up the ante, and see if we can make it interactive so you can enter the number of days from now the task is due.

(yas-global-mode)
(with-temp-buffer
  (insert "# name : todo-followup
# --

*************** TODO $1
${2:             DEADLINE: `(let ((ndays (seconds-to-time (* (string-to-int (read-from-minibuffer \"Days until due: \")) 24 60 60))))
  (format-time-string \"<%Y-%m-%d %a>\" (time-add (current-time) ndays)))`}$0
*************** END 
")
  (yas-load-snippet-buffer-and-close 'org-mode))
*************** TODO sweet!
		DEADLINE: <2014-02-26 Wed>
*************** END

Well, that made it just a bit sweeter! I was prompted for the "Days until due:", entered 10 days, and a date 10 days from now was automatically entered!

Copyright (C) 2014 by John Kitchin. See the License for information about copying.

org-mode source

Org-mode version = 8.2.5h

Discuss on Twitter

Invisible text in emacs

| categories: emacs | tags:

Emacs supports invisible text . In other words, you can use code to set properties on text in a buffer that make it visible, or invisible. You can use code to change the invisibility properties of text.

I have been exploring ways to conditionally navigate in org documents using links. These links may validate that some property has been set in a heading, for example. An alternative approach is to make regions visible, depending on some criteria. That is what we do today. You will probably want to see this video , since what happens in this post is dynamic, and you will not see visible and invisible text.

What I have below here are a set of headings with properties that indicate what "level" they are at: beginner, medium and advanced. First, we mark each org subtree with an overlay that has an 'invisible property that contains the "level". Then, we add the "level" to the list of symbols that marks invisible sections. If you run this block, the headings all disappear.

(org-map-entries (lambda () 
                   (let ((level (org-entry-get (point) "level"))
                          (symbol-level))
                     (when level
                       (setq symbol-level (intern level))
                       (org-mark-subtree)                 
                       (overlay-put (make-overlay (point) (mark))
                                    'invisible 
                                    symbol-level)
                       ;; make regions with symbol-level invisible
                       (add-to-invisibility-spec `(,symbol-level))))))

Now, we can selectively make them appear with these links.

elisp:(remove-from-invisibility-spec '(beginner))

elisp:(remove-from-invisibility-spec '(medium))

elisp:(remove-from-invisibility-spec '(advanced))

I imagine this could be useful to show selective content based on user choices. I am not sure it is better than links to external files. I imagine you would have to open this org file by some elisp command that would run the block at the top to make everything invisible, and then show it to the user. You could definitely build in more complex code to determine if a user was allowed to open a section.

(defun level2-p ()
  "return if user is ready for level 2 based on value of property named correct"
  (interactive)
  (save-excursion
    (org-open-link-from-string "[[#beginner]]")
    (let ((val (org-entry-get (point) "correct")))
      (if (and val (string= val "true"))
          t
        nil))))
level2-p

Now, we can build this link:

elisp:(when (level2-p) (remove-from-invisibility-spec '(medium)))

This will show the medium level, provided we have already opened the beginner level and set the property value correctly.

1 subsection 1

some text in 1

2 subsection 2

more text in 2

3 subsection 3

last section 3

Copyright (C) 2014 by John Kitchin. See the License for information about copying.

org-mode source

Org-mode version = 8.2.5h

Discuss on Twitter

Send email to a list of users

| categories: emacs, emacs-lisp | tags:

I have a need to send a lot of emails to users in my class. I have to send each student an email containing there userid and a password assigned to them. I have a list of these, so the strategy is to create a function that will email that information to one user, and then use mapcar to apply the function to each pair in a list. First, we work out a function that will send one email to one user.

(defun send-mail (userid password)
  "send email to userid@andrew.cmu.edu containing their password"
  (interactive)
  (mail)
  (mail-to)
  (insert (format "%s@andrew.cmu.edu" userid))
  (mail-subject)
  (insert "[06-640] account information")
  (mail-text)
  (insert (format "
An account has been created on gilgamesh.cheme.cmu.edu
userid: %s
password: %s" userid password))
  (mail-send-and-exit))

(send-mail "jkitchin" "trustme99")

That worked well. I ran the block and got the email.

Now, suppose I have this data:

userid password
user1 trustme99
user2 foolme99
user3 blameme99

We can pass that to a source block as a list of lists that will look like this:

 ((user1 trustme99) (user2 foolme99) (user3 blameme99))

Then, we can use a mapcar to process each element. Here I use a dummy function with two arguments. If I substitute the function above, each of these users would get an email.

(defun fun (a b)
  (princ (format "user: %s\npassword: %s\n" a b)))

(mapcar (lambda (x) (fun (car x) (cadr x))) data)
user: user1
password: trustme99
user: user2
password: foolme99
user: user3
password: blameme99

I am not sure that is the best way to get the first and second elements in the list element. It looks funny to me, but it works fine. the alternative is not much prettier:

(defun fun (a b)
  (princ (format "user: %s\npassword: %s\n" a b)))

(mapcar (lambda (x) (fun (nth 0 x) (nth 1 x))) data)
user: user1
password: trustme99
user: user2
password: foolme99
user: user3
password: blameme99

Copyright (C) 2014 by John Kitchin. See the License for information about copying.

org-mode source

Discuss on Twitter

Custom directives

| categories: emacs, org-mode | tags:

You can define custom special blocks in org-mode. Here is an example of creating attention and note directives. Note you need to specify the styles and environments in the header like this:

#+HTML_HEAD_EXTRA:  <style>.attention {font-size: 30px; text-indent: 50px; color: red; background-color:HotPink;}</style>
#+HTML_HEAD_EXTRA:  <style>.note {font-size: 30px; text-indent: 50px; background-color:LightSkyBlue;}</style>

#+LATEX_HEADER: \usepackage[usenames,dvipsnames,svgnames,table]{xcolor}
#+LATEX_HEADER: \newenvironment{attention}{\color{red}}{\ignorespacesafterend}
#+LATEX_HEADER: \newenvironment{note}{\itshape}{\ignorespacesafterend}

That allows you to define different looks for exporting to html and LaTeX. For the blog post, I put the style in the body of the html.

Here is the markup for an attention block.

#+BEGIN_ATTENTION
Pay attention to this text!
#+END_ATTENTION

Renders like this:

Pay attention to this text!

A note is defined as:

#+begin_note
this is a note
#+end_note

and it renders like this:

this is a note.

I am not sure if it is possible to add arguments, e.g. via attributes. Anyway, this may enable some flexibility in adding content that may be rendered in html and LaTeX in org-mode. There is a function (org-html-special-block and org-latex-special-block) that does the rendering, and it has an info plist that probably has the information. It does not appear you can pass arguments in though. That would require a filter that redefines the rendering.

Copyright (C) 2013 by John Kitchin. See the License for information about copying.

org-mode source

Discuss on Twitter

Posting articles to CiteULike from bibtex

| categories: emacs, citeulike, python | tags:

Table of Contents

I have been using CiteULike for a while now to keep a list of articles that are probably worth reading. Basically, each month I get a table of contents from many journals, and as I read through them, if an article catches my attention I add it to my CiteULike account.

This list is not synchronized with my bibtex database however. These serve different purposes. The CiteULike list is for articles that are probably worth reading, while the bibtex file contains articles I am probably going to cite. It should be that every article in my bibtex file is on CiteULike, but not necessarily the other way around. The problem is I do not have a way to push files from my bibtex file to CiteULike easily.

CiteULike allows you to import a bibtex file though. I want to explore automatically importing a bibtex file by simulating the form. We need a set of cookies to make this happen so CiteULike knows who we are. I stored my username and password in a file called citeulike.json and use them to get cookies that I save here in a pickle file. I think this cookie gives you access to your CiteULike account, so it should be kept secret.

import json, pickle, requests

with open('citeulike.json') as f:
    d = json.loads(f.read())

url = 'http://www.citeulike.org/login.do'

data = "username={0}&password={1}&perm=1".format(d['username'], d['password'])

r = requests.post(url, data=data, allow_redirects=False)

with open('cookies.pckl', 'wb') as f:
    pickle.dump(r.cookies, f)

By inspecting the import page with Firebug, I constructed this http request to upload a bibtex string.

import pickle, requests

# reload cookies
with open('cookies.pckl', 'rb') as f:
    cookies = pickle.load(f)

url = 'http://www.citeulike.org/profile/jkitchin/import_do'

bibtex = '''
@article{zhuo-2010-co2-induc,
  author =       {Zhuo, Shengchi and Huang, Yongmin and Peng, Changjun
                  and Liu, Honglai and Hu, Ying and Jiang, Jianwen},
  title =        {CO2-Induced Microstructure Transition of Surfactant
                  in Aqueous Solution: Insight from Molecular Dynamics
                  Simulation},
  journal =      {The Journal of Physical Chemistry B},
  volume =       114,
  number =       19,
  pages =        {6344-6349},
  year =         2010,
  doi =          {10.1021/jp910253b},
  URL =          {http://pubs.acs.org/doi/abs/10.1021/jp910253b},
  eprint =       {http://pubs.acs.org/doi/pdf/10.1021/jp910253b}
}'''

data = {'pasted':bibtex,
        'to_read':2,
        'tag_parsing':'simple',
        'strip_brackets':'no',
        'update_id':'bib-key',
        'btn_bibtex':'Import BibTeX file ...'}

headers = {'content-type': 'multipart/form-data',
           'User-Agent':'jkitchin/johnrkitchin@gmail.com bibtexupload'}

r = requests.post(url, headers=headers, data=data, cookies=cookies, files={})

The result is that article is now listed in my CiteULike at http://www.citeulike.org/user/jkitchin/article/12728895 . This opens the possibility of integrating this into my bibtex workflow. I could implement this in emacs-lisp, and have it automatically upload new entries in the bibtex file to CiteULike.

1 Doing this in emacs

I think the easiest thing to do here is to write a python script that takes the bibtex string and posts it. We will use emacs to get the bibtex string. We will use the example at http://ergoemacs.org/emacs/elisp_perl_wrapper.html to put this together. This example uses an external script that takes a string on stdin, and returns a result on stdout.

We will run the function in a bibtex buffer. We will narrow the buffer to the current entry, and use that to define the boundaries of the string. We do the command in a temp-buffer to prevent it from modifying our bibtex file. There is some way to make the command not do this with optional arguments, but I did not figure it out. It is a little ugly I had to use an absolute path below. An alternative would be to put the script into a directory on your path. Here is the function.

(defun j/upload-bibtex-entry-to-citeulike ()
  "get bibtex string and submit to citeulike"
  (interactive)
  (save-restriction
    (bibtex-narrow-to-entry)
    (let ((startpos (point-min))
          (endpos (point-max))
          (bibtex-string (buffer-string))
          (script "python c:/Users/jkitchin/Dropbox/blogofile-jkitchin.github.com/_blog/upload_bibtex_citeulike.py"))
      (with-temp-buffer (insert bibtex-string)
                        (shell-command-on-region (point-min) (point-max) script t nil nil t)))))

Now, let us define the python script.

#!python
import pickle, requests, sys

# reload cookies
with open('c:/Users/jkitchin/Dropbox/blogofile-jkitchin.github.com/_blog/cookies.pckl', 'rb') as f:
    cookies = pickle.load(f)

url = 'http://www.citeulike.org/profile/jkitchin/import_do'

bibtex = sys.stdin.read()

data = {'pasted':bibtex,
        'to_read':2,
        'tag_parsing':'simple',
        'strip_brackets':'no',
        'update_id':'bib-key',
        'btn_bibtex':'Import BibTeX file ...'}

headers = {'content-type': 'multipart/form-data',
           'User-Agent':'jkitchin/johnrkitchin@gmail.com bibtexupload'}

r = requests.post(url, headers=headers, data=data, cookies=cookies, files={})

That is it. Now, in my bibtex file with the cursor in an entry, I type M-x j/upload-bibtex-entry-to-citeulike, and a few seconds later the entry has been uploaded!

Copyright (C) 2013 by John Kitchin. See the License for information about copying.

org-mode source

Discuss on Twitter
« Previous Page -- Next Page »