2009-04-05

remember

remember

[ UPDATE: I have cleaned up the code; it should work better now if you don't have an open emacsclient. I also removed the comments relating to that, as to not confuse people…]

The human brain is quite good at forgetting things. Often, this is a good thing. However, sometimes you might actually not want to forget. Things you need to do – 'Buy milk', 'Register for Helsinki City Run', or simply things that might be of interest, such as books, funny quotations, articles to check out, and so on.

Such thoughts should me jotted down immediately, without thinking too much. It's an essential part of productivity methods like GTD ('Getting Things Done'). The idea is that you capture ideas, thoughts, plans, etc. at the very moment they enter your mind.

Periodically, you go through all the things you gathered, and decide what to do with them. Maybe you need to take some action, maybe you only need to store it somewhere. Or maybe you can simply throw it away. The main point is that whenever something is in your mind that might be interesting later, make sure it's not lost.

You can of course carry a simple notebook around and that's not a bad idea at all. However, a large part of the information inflow is digitized, computerized, and it's not very convenient to copy interesting tidbits by hand from your notebook. Clearly, our almighty emacs should be able to help with this, or?

Indeed. The Emacs-way to capture dispersed information is called remember-mode. It allows you to quickly write down your thoughts, press C-c C-c and be done with it. The important thing is that is should be a mindless little exercise to save these things, and get on with your work, life.

I'll describe my use of remember-mode in combination with org-mode. There are many other things you can do with remember-mode; just read the manual or the cookbook; also see the great tutorial, and the remember-mode section in the org-mode-manual.

To integrate remember-mode with org-mode, add to your .emacs:

(org-remember-insinuate)

Now, the important thing is to have 'remember' available anywhere on your desktop, not just when using emacs – after all, valuable ideas might come up even when not using emacs, for example when browsing the web. Jack Moffit showed how to get little pop-up windows for remember on MacOS; inspired by that, here is my solution for Linux/X (this is an updated version):

;; you might also want to set:
;;   (setq org-agenda-skip-unavailable-files t)
;; so these warnings won't annoy the little remember-frame
;; also: I have noted infrequent problems when using ElScreen
;;  (the wrong frame might be chosen for Remember in about 10% of the cases)

(defun djcb-remember-frame ()
  "turn the current frame into a small popup frame for remember mode;
this is meant to be called with 
     emacsclient -c -e '(djcb-remember-frame)'"
  (modify-frame-parameters nil
    '( (name . "*Remember*") ;; must be same as in mode-hook below  
       (width .  80)
       (height . 10)
       (vertical-scroll-bars . nil)
       (menu-bar-lines . nil)
       (tool-bar-lines . nil)))
  (org-remember)
  (when (fboundp 'x-focus-frame) (x-focus-frame nil)) ;; X only....

  (delete-other-windows)) 

;; when we're in such a remember-frame, close it when done.
(add-hook 'org-remember-mode-hook
  (lambda()
    (define-key org-remember-mode-map (kbd "C-c C-c")
      '(lambda()(interactive)
         (let ((remember-frame-p 
                 (string= (frame-parameter nil 'name) "*Remember*")))
           (when remember-frame-p (make-frame-invisible))  ;; hide quickly

           (org-remember-finalize)
           (when remember-frame-p (delete-frame)))))))

The next step is to have some easy way to run this. I am using emacsclient and xbindkeys for that. In my ~/.xbindkeysrc I have:

# pop-up a remember window
"emacsclient -c -e '(make-remember-frame)'"
  control+shift+r

After this (and assuming a running emacs daemon), you can run remember-mode by pressing Control-Shift-r. Make it part of your routine; whenever an idea comes up, press Control-Shift-r, quickly jot down the thing on your mind, and press C-c C-c to save it for eternity. Review your notes periodically.

Finally, as mentioned, remember-mode can do quite a bit more than described here - especially when used in combination with org-mode. One interesting extension are templates, which are a way to create your notes in a structured way. For example, I have the following:

(setq org-remember-templates 
  '(("Clipboard" ?c "* %T %^{Description}\n %x"
      "~/remember.org" "Interesting")
     ("ToDo" ?t "* TODO %T %^{Summary}" 
       "~/remember.org" "Todo")))

Please refer to the manual for the exact syntax. Basically, this defines two templates; the first one will ask you for a description, and then add then insert the contents of the (X) clipboard under the 'Interesting'-header; the second insert a simple 'TODO'-entry under the 'Todo'-header.

Exempli gratia – suppose I have selected some text in my web-browser. Now, I push the key-binding we set up before: C-R (Control-Shift r). A small window pops up, asking me if I want to make a 'Clipboard' or a 'Todo' entry. I press c for a clipboard entry. I asks me for a description, which I provide; it dumps the contents of the clipboard in the entry. I then push C-c C-c to save and close the pop-up window.

All of the notes will be saved to a file ~/remember.org; you can customize this of course, and you can also move different kinds of today items to different files. Anyway, after a while, ~/remember.org might look somewhat like this:

* Interesting
** <2009-04-05 Sun 18:06> what is emacs?

  Emacs is a powerful, customizable, self-documenting, modeless text
  editor. Emacs contains special code editing features, a scripting language
  (elisp), and the capability to read mail, news, and more without leaving the
  editor.
** <2009-04-05 Sun 19:39> socrates
  The hour of departure has arrived, and we go our ways - I to die, and you to
  live. Which is better God only knows.
* Todo
** TODO <2009-04-05 Sun 18:12> buy milk & cookies

As you see, remember.org is just another org-mode-file, so all its bells and whistles are available. Periodically, you should go through this file and take necessary actions.

You could go further and develop complicated templates for capturing specific information, tagging it and so on. The various manuals give some examples. All I wanted to do here is to give a small taste of the power of remember-mode in combination with org-mode. The rest is up to your imagination…

7 comments:

Ryan said...

You can do all of that much more easily like this:

(defcustom remember-frame-alist nil
"Additional frame parameters for dedicated rememebr frame."
:type 'alist
:group 'remember)

(defadvice remember (around remember-frame-parameters activate)
"Set some frame parameters for the remember frame."
(let ((default-frame-alist (append remember-frame-alist default-frame-alist)))
ad-do-it))

Then M-x customize-variable remember-frame-alist and add width 80 and height 10.

In your xbindkeys config, use remember-other-frame instead of make-remember-frame.

This has the added bonus of making C-g do the right thing (i.e. close the remember frame) while selecting a template.

Folcon said...

Thanks I appreciate the help, though its not completely solved my problem I have a mostly working solution... Hmm I'll have to do a bit more debugging till I get it fixed :D.

djcb said...

@Folcon: I've updated the code; hope this fixes your problem.

@Ryan: I've incorporated some of your ideas.

rodprice said...

Ryan's solution using emacs advice above works for me, but I had to alter the command given to xbindkeys to "emacsclient -e '(remember-other-frame)'" to get it to stop opening two frames.

Anonymous said...

The remember-frame keeps popping up very briefly and dissapears again with the original setting. However, if I use rodprice's settings I get two emacs frames, both ignoring the width and height settings...

I don't know where to look for a solution. I'am using emacs snapshot and would love to have this working.

Vladimir said...

It's really nice hack, but emacsclient process keeps running after closing frame.

Ryan said...

Ha! I think I solved the problem where you either get an extra frame, or your remember frame disappears right after appearing. The problem is that emacs acts a little oddly if the one and only frame currently in existence was created by emacsclient itself. This is the case if you do emacsclient -e '(remember-other-frame)'. You can work around this by using the -c option to create a new frame, but then you have an extra frame lying around.

So, to fix this, my basic idea was to create a "sacrificial" frame, then do what I wanted to do, then delete the sacrificial frame. This seems to work. To do this, put the following in your .emacs somewhere:

(defmacro with-invisible-background-frame (&rest body)
"Like `progn', but evaluates the body after creating a new
frame and making it invisible. After the body is evaluated,this
background frame is deleted. Also, any errors are ignored in
the body, because I can't fathom emacs' error-handling
functions. This function exists to work around one of the
quirks of emacsclient."

`(let ((sacrificial-frame (make-frame)))
(make-frame-invisible sacrificial-frame)
(ignore-errors ,@body)
(delete-frame sacrificial-frame)))

That function (actually a macro, but whatever) will create a sacrificial frame, make it invisible, do your stuff, then delete that frame. Since all your commands get executed while a frame already exists, your commands shouldn't trigger the weird behavior described above, and so they should not be deleted.

Here's an example. Suppose you have an emacs dameon with no open frames, and you run the following at the command-line:

emacsclient -e '(remember-other-frame)'

What probably happens is that the remember frame appears and then disappears before you can do anything with it. Now, try this instead:

emacsclient -d "$DISPLAY" -e '(with-invisible-background-frame (remember-other-frame))'

You should get what you want, a remember frame that doesn't disappear. The sacrificial frame may be visible for a split second.

Oh, and you'll probably have to use something like emacsclient -d "$DISPLAY" to tell emacsclient which display to use.