6089 comments
2357 subscribers
6234 on Twitter
Subscribe! Feed reader E-mail

Reading these posts, you can probably tell that I really, really like the Emacs text editor.

View my Emacs configuration.

Check out Planet Emacsen to read other Emacs geeks’ blogs. For all things Emacs, check out the EmacsWiki.

On this page:

Emacs Chat with Avdi Grimm (Org-mode, Ruby, etc.)

Update 2013-03-16: Get the MP3 or Ogg Vorbis files, or listen to them on archive.org!

Thanks to Matthew Darling’s comment on my post about code coaching, I came across Avdi Grimm’s work with pair programming – and was delighted to find that he uses Emacs too. =) Check out my Skype chat with Avdi about Org-mode literate programming, Ruby, and how he got started with Emacs.

Emacs Chat with Avdi Grimm from Sacha Chua on Vimeo.

If you liked this, you might also like my chat with John Wiegley. Do you use Emacs? Want to share your story and the nifty things you think other people should know about? Comment below or get in touch with me!

Short URL: http://sachachua.com/blog/p/24540

Rediscovering Emacs features, or what to do after you get carried away installing packages

A kid in a candy store – that’s me with M-x list-packages, EmacsWiki pages, Planet Emacsen, and other sources of Emacs goodness. Because Emacs has so much functionality and people keep adding stuff to it, it’s easy to forget about the cool goodies in configuration files and the Emacs codeverse. It’s important to practise and review, though, because there are all sorts of great keyboard shortcuts and commands that could make Emacs even better if I could just drill them into my brain.

Spaced repetition is a great technique for prioritizing and learning things. Emacs Org has an org-drill module that implements flashcards for Org headings that are tagged with :drill:. I’ve been using this to prepare for the Canadian citizenship exam, and that’s been working out well. So I started creating an emacs-drill.org file with headings for the things I’m interested in learning, such as multiple-cursor-mode and ace-jump-mode…

… And then I remembered, hey, my Emacs configuration is one big Org file (thanks to the joys of literate programming) so why don’t I just stick the :drill: tag onto the relevant snippets and run M-x org-drill there?

This might actually work out. =)

I was thinking of doing some kind of idle-timer hook, but I actually don’t mind manually triggering it. Besides, I’m experimenting with John Wiegley’s org-agenda display paired with winner-mode to save my window configuration.

Come to think of it, it might be good to add a random Emacs keybinding to the org-agenda display. I’ve installed keywiz, so I can reuse some of the code from that:

(use-package keywiz)
(defun sacha/load-keybindings ()
  "Since we don't want to have to pass through a keywiz game each time..."
  (setq keywiz-cached-commands nil)
  (do-all-symbols (sym)
    (when (and (commandp sym)
               (not (memq sym '(self-insert-command
                                digit-argument undefined))))
      (let ((keys (apply 'nconc (mapcar
                                 (lambda (key)
                                   (when (keywiz-key-press-event-p key)
                                     (list key)))
                                 (where-is-internal sym)))))
        ;;  Politically incorrect, but clearer version of the above:
        ;;    (let ((keys (delete-if-not 'keywiz-key-press-event-p
        ;;                               (where-is-internal sym))))
        (and keys
             (push (list sym keys) keywiz-cached-commands)))))))
  (sacha/load-keybindings)
  ;; Might be good to use this in org-agenda...
  (defun sacha/random-keybinding ()
    "Describe a random keybinding."
    (let* ((command (keywiz-random keywiz-cached-commands))
         (doc (and command (documentation (car command)))))
      (if command
          (concat (symbol-name (car command)) " "
                  "(" (mapconcat 'key-description (cadr command) ", ") ")"
                  (if doc
                      (concat ": " (substring doc 0 (string-match "\n" doc)))
                    ""))
"")))

… and a minor adjustment to org-agenda-custom-commands…

(defun sacha/org-agenda-with-tip (arg) (org-agenda-list arg) (let ((inhibit-read-only t)) (insert (sacha/random-keybinding) “\n”))) (setq org-agenda-custom-commands `((“a” “Agenda” sacha/org-agenda-with-tip) (“T” todo-tree “TODO”)
;; more here; see my config file
)))

… and now I see a random Emacs keybinding every time I review my to-do list.

agenda-tip

If you find yourself forgetting to revisit the nifty Emacs snippets you’ve added to your configuration, add reminders for yourself. Make yourself some flashcards with org-drill.el or flashcard.el and give that a try, or integrate reminders into your workflow. Have fun!

Short URL: http://sachachua.com/blog/p/24527

Emacs Org: Task-related keyboard shortcuts for the agenda

I really love the way you can tweak Emacs’ keyboard shortcuts and functionality to fit the way you want to work. Here are three keyboard shortcuts I’ve added to my Org agenda to make it even easier to work with tasks.

x: Mark the current task as done. Same as typing t x, but somehow it feels like it has more oomph as a single-character shortcut.

X: Mark the current task as done and create a new task at the same level, taking advantage of the task template I’d previously created in org-capture-templates.

N: Create a new note or task at the current position.

Make it easy to mark a task as done

(defun sacha/org-agenda-done (&optional arg)
  "Mark current TODO as done.
This changes the line at point, all other lines in the agenda referring to
the same tree node, and the headline of the tree node in the Org-mode file."
  (interactive "P")
  (org-agenda-todo "DONE"))
;; Override the key definition for org-exit
(define-key org-agenda-mode-map "x" 'sacha/org-agenda-done)

Make it easy to mark a task as done and create a follow-up task

  (defun sacha/org-agenda-mark-done-and-add-followup ()
    "Mark the current TODO as done and add another task after it.
Creates it at the same level as the previous task, so it's better to use
this with to-do items than with projects or headings."
    (interactive)
    (org-agenda-todo "DONE")
    (org-agenda-switch-to)
    (org-capture 0 "t"))
;; Override the key definition
(define-key org-agenda-mode-map "X" 'sacha/org-agenda-mark-done-and-add-followup)

Capture something based on the agenda position

(defun sacha/org-agenda-new ()
  "Create a new note or task at the current agenda item.
Creates it at the same level as the previous task, so it's better to use
this with to-do items than with projects or headings."
  (interactive)
  (org-agenda-switch-to)
  (org-capture 0))
;; New key assignment
(define-key org-agenda-mode-map "N" 'sacha/org-agenda-new)

Check out my Emacs configuration for other ideas.

Short URL: http://sachachua.com/blog/p/24335

Emacs Org: Display projects with a few subtasks in the agenda view

I wanted a view that showed projects with a few subtasks underneath them. That way, I could quickly scan my projects and make a little progress on each of them. Here’s a sample of the output showing a few of my projects:

Headlines with TAGS match: +PROJECT
Press `C-u r' to search again with new search string
  organizer:  Set up communication processes for Awesome Foundation Toronto
  organizer:  TODO Announce the next pitch night
  organizer:  TODO Follow up with the winner of the previous pitch night for any news to include in the updates

  organizer:  Tidy up the house so that I can find things quickly
  organizer:  TODO Inventory all the things in closets and boxes         :@home:
  organizer:  TODO Drop things off for donation                       :@errands:

  organizer:  Learn how to develop for Android devices

Here are the user-defined functions that set this up:

(defun sacha/org-agenda-project-agenda ()
  "Return the project headline and up to `sacha/org-agenda-limit-items' tasks."
  (save-excursion
    (let* ((marker (org-agenda-new-marker))
           (heading
            (org-agenda-format-item "" (org-get-heading) (org-get-category) nil))
           (org-agenda-restrict t)
           (org-agenda-restrict-begin (point))
           (org-agenda-restrict-end (org-end-of-subtree 'invisible))
           ;; Find the TODO items in this subtree
           (list (org-agenda-get-day-entries (buffer-file-name) (calendar-current-date) :todo)))
      (org-add-props heading
          (list 'face 'default
                'done-face 'org-agenda-done
                'undone-face 'default
                'mouse-face 'highlight
                'org-not-done-regexp org-not-done-regexp
                'org-todo-regexp org-todo-regexp
                'org-complex-heading-regexp org-complex-heading-regexp
                'help-echo
                (format "mouse-2 or RET jump to org file %s"
                        (abbreviate-file-name
                         (or (buffer-file-name (buffer-base-buffer))
                             (buffer-name (buffer-base-buffer))))))
        'org-marker marker
        'org-hd-marker marker
        'org-category (org-get-category)
        'type "tagsmatch")
      (concat heading "\n"
              (replace-regexp-in-string "^" "  "
                                        (org-agenda-finalize-entries list))))))

  (defun sacha/org-agenda-projects-and-tasks (match)
    "Show TODOs for all `org-agenda-files' headlines matching MATCH."
    (interactive "MString: ")
    (let ((todo-only nil))
      (if org-agenda-overriding-arguments
          (setq todo-only (car org-agenda-overriding-arguments)
                match (nth 1 org-agenda-overriding-arguments)))
      (let* ((org-tags-match-list-sublevels
              org-tags-match-list-sublevels)
             (completion-ignore-case t)
             rtn rtnall files file pos matcher
             buffer)
        (when (and (stringp match) (not (string-match "\\S-" match)))
          (setq match nil))
        (setq matcher (org-make-tags-matcher match)
              match (car matcher) matcher (cdr matcher))
        (catch 'exit
          (if org-agenda-sticky
              (setq org-agenda-buffer-name
                    (if (stringp match)
                        (format "*Org Agenda(%s:%s)*"
                                (or org-keys (or (and todo-only "M") "m")) match)
                      (format "*Org Agenda(%s)*" (or (and todo-only "M") "m")))))
          (org-agenda-prepare (concat "TAGS " match))
          (org-compile-prefix-format 'tags)
          (org-set-sorting-strategy 'tags)
          (setq org-agenda-query-string match)
          (setq org-agenda-redo-command
                (list 'org-tags-view `(quote ,todo-only)
                      (list 'if 'current-prefix-arg nil `(quote ,org-agenda-query-string))))
          (setq files (org-agenda-files nil 'ifmode)
                rtnall nil)
          (while (setq file (pop files))
            (catch 'nextfile
              (org-check-agenda-file file)
              (setq buffer (if (file-exists-p file)
                               (org-get-agenda-file-buffer file)
                             (error "No such file %s" file)))
              (if (not buffer)
                  ;; If file does not exist, error message to agenda
                  (setq rtn (list
                             (format "ORG-AGENDA-ERROR: No such org-file %s" file))
                        rtnall (append rtnall rtn))
                (with-current-buffer buffer
                  (unless (derived-mode-p 'org-mode)
                    (error "Agenda file %s is not in `org-mode'" file))
                  (save-excursion
                    (save-restriction
                      (if org-agenda-restrict
                          (narrow-to-region org-agenda-restrict-begin
                                            org-agenda-restrict-end)
                        (widen))
                      (setq rtn (org-scan-tags 'sacha/org-agenda-project-agenda matcher todo-only))
                      (setq rtnall (append rtnall rtn))))))))
          (if org-agenda-overriding-header
              (insert (org-add-props (copy-sequence org-agenda-overriding-header)
                          nil 'face 'org-agenda-structure) "\n")
            (insert "Headlines with TAGS match: ")
            (add-text-properties (point-min) (1- (point))
                                 (list 'face 'org-agenda-structure
                                       'short-heading
                                       (concat "Match: " match)))
            (setq pos (point))
            (insert match "\n")
            (add-text-properties pos (1- (point)) (list 'face 'org-warning))
            (setq pos (point))
            (unless org-agenda-multi
              (insert "Press `C-u r' to search again with new search string\n"))
            (add-text-properties pos (1- (point)) (list 'face 'org-agenda-structure)))
          (org-agenda-mark-header-line (point-min))
          (when rtnall
            (insert (mapconcat 'identity rtnall "\n") ""))
          (goto-char (point-min))
          (or org-agenda-multi (org-agenda-fit-window-to-buffer))
          (add-text-properties (point-min) (point-max)
                               `(org-agenda-type tags
                                                 org-last-args (,todo-only ,match)
                                                 org-redo-cmd ,org-agenda-redo-command
                                                 org-series-cmd ,org-cmd))
          (org-agenda-finalize)
          (setq buffer-read-only t)))))

… and the relevant snippet from my org-agenda-custom-commands:

(setq org-agenda-custom-commands 
      '(
        ;; ... other stuff goes here
        ("2" "List projects with tasks" sacha/org-agenda-projects-and-tasks
         "+PROJECT"
         ((sacha/org-agenda-limit-items 3)))
        ;; ... other stuff goes here
        ))

See this in context in my Emacs configuration.

Short URL: http://sachachua.com/blog/p/24312

Emacs Org: Display a subset of tasks by context

I wanted to get a quick preview of my top three tasks by context. Since org-tags-view didn’t seem to have a built-in way to limit the
number of displayed items, I used defadvice to add my own. Here’s the relevant code from my Emacs configuration:

(defvar sacha/org-agenda-limit-items nil "Number of items to show in agenda to-do views; nil if unlimited.")
(defadvice org-agenda-finalize-entries (around sacha activate)
  (if sacha/org-agenda-limit-items
      (progn
        (setq list (mapcar 'org-agenda-highlight-todo list))
        (if nosort
          (setq ad-return-value
            (subseq list 0 sacha/org-agenda-limit-items))
          (when org-agenda-before-sorting-filter-function
            (setq list (delq nil (mapcar org-agenda-before-sorting-filter-function list))))
          (setq ad-return-value
                (mapconcat 'identity
                           (subseq
                            (sort list 'org-entries-lessp)
                            0
                            sacha/org-agenda-limit-items)
                           "\n"))))
    ad-do-it))

and the snippet from my org-agenda-custom-commands:

(setq org-agenda-custom-commands
  '(
    ;; ... other commands go here
    ("0" "Block agenda"
         ((tags-todo "+@phone")
          (tags-todo "+@work")
          (tags-todo "+@drawing")
          (tags-todo "+@coding")
          (tags-todo "+@writing")
          (tags-todo "+@computer")
          (tags-todo "+@home"))
         ((org-agenda-sorting-strategy '(priority-up effort-down))
          (sacha/org-agenda-limit-items 3)))
        (")" "Block agenda"
         ((tags-todo "+@phone")
          (tags-todo "+@work")
          (tags-todo "+@drawing")
          (tags-todo "+@coding")
          (tags-todo "+@writing")
          (tags-todo "+@computer")
          (tags-todo "+@home"))
         ((org-agenda-sorting-strategy '(priority-down effort-down))
          (sacha/org-agenda-limit-items nil)))
        ("9" "Unscheduled by context"
         ((tags-todo "+@phone")
          (tags-todo "+@work")
          (tags-todo "+@drawing")
          (tags-todo "+@coding")
          (tags-todo "+@writing")
          (tags-todo "+@computer")
          (tags-todo "+@home"))
         ((org-agenda-skip-function
           (lambda nil
             (org-agenda-skip-entry-if (quote scheduled) (quote deadline)
                                       (quote regexp) "\n]+>")))
          (org-agenda-sorting-strategy '(priority-down effort-down))
          (sacha/org-agenda-limit-items 3)))
    ;; ... more after this
))

This way, I can see all of my common contexts on one screen, and I can decide what I want to work on first.

Short URL: http://sachachua.com/blog/p/24310

Emacs: Strike through headlines for DONE tasks in Org

I wanted a quick way to visually distinguish DONE tasks from tasks I still need to do. This handy snippet from the Emacs Org-mode mailing list does the trick by striking through the headlines for DONE tasks.

image

Here’s the code:

(setq org-fontify-done-headline t)
(custom-set-faces
 '(org-done ((t (:foreground "PaleGreen"   
                 :weight normal
                 :strike-through t))))
 '(org-headline-done 
            ((((class color) (min-colors 16) (background dark)) 
               (:foreground "LightSalmon" :strike-through t)))))

View my Emacs configuration

Short URL: http://sachachua.com/blog/p/24270

How to build MobileOrgNG for Android

MobileOrgNG is kvj’s fork of matburt’s MobileOrg for Android. It has a better layout for large devices and a useful outline view, but doesn’t have some of the other features in the main branch. Here’s how you can build it in Eclipse.

In order to be able to get all the libraries you’ll need, install the Subversive SVN plugin for Eclipse.

  1. In Eclipse, click Help – Install New Software.
  2. Click on the dropdown for Work with and choose the update site for your Eclipse version (ex: Juno).
  3. When the packages load, type in Subversive to filter the list.
  4. Choose Subversive SVN Team Provider. You can choose other plugins as well.
  5. Click Next and proceed through the installation process.

Now you can check out the MobileOrgNG source code and other modules. MobileOrgNG is set up as an Eclipse project, so importing it is easier than importing the original MobileOrg. Here’s how to get MobileOrgNG:

  1. Copy the Git repository URI (ex: git://github.com/kvj/mobileorg-android.git)
  2. In Eclipse, click File – Import – Git – Projects from Git.
  3. Choose URI.
  4. The URI may automatically be detected from the clipboard. If it isn’t, paste it in.
  5. Click Next.
  6. Click Next again.
  7. Click Next.
  8. You should now be at the dialog called Select a wizard to use for importing projects. Choose Import existing projects and click Next.
  9. It should have detected the mobile-org project. Click Finish.

In addition to MobileOrgNG, you will also need the android-actionbar and android-file-dialog libraries. Here’s how to get android-actionbar:

  1. Go to https://github.com/kvj/android-actionbar and copy the Git repository URL (ex: git://github.com/kvj/android-actionbar.git).
  2. In Eclipse, click File – Import – Git – Projects from Git.
  3. Choose URI.
  4. The URI may automatically be detected from the clipboard. If it isn’t, paste it in.
  5. Click Next.
  6. Click Next again.
  7. In the Local destination dialog, change Initial branch to honeycomb-support. Click Next.
  8. You should now be at the dialog called Select a wizard to use for importing projects. Click Cancel.
  9. Click File – Import – Android – Existing Android Code Into Workspace.
  10. Click Browse and choose the android-actionbar directory in your workspace. You can deselect the actionbar example if you wish.
  11. Click Finish.

Here’s how to get android-file-dialog.

  1. Go to http://code.google.com/p/android-file-dialog/source/checkout and copy the SVN URI (ex: http://android-file-dialog.googlecode.com/svn/trunk/).
  2. In Eclipse, click on File – Import – SVN – Project from SVN.
  3. Paste in the URI.
  4. Click Next.
  5. Eclipse should prompt you to normalize the URL. Click Yes.
  6. Click Browse. Choose trunk and click OK.
  7. Click Finish.
  8. Choose Find projects in the children of the selected resource. Click Finish.
  9. Make sure that Check out as a projects into workspace is selected. Click Finish.

Confirm that the libraries are detected.

  1. Right-click on the mobileorg-android project and choose Properties.
  2. Click Android and confirm that both libraries are detected. If not, you may need to remove and re-add them.

The Dropbox API key isn’t part of the source code, so you’ll need to apply for your own at https://www.dropbox.com/developers/start . After you get the API key, add it to your project:

  1. Create a new Android XML Values file. I called mine secrets.xml.
  2. Right-click on the file and choose Team – Ignore.
  3. Add a string with the key dropbox_consumer_key and the value from the Dropbox webpage.
  4. Add another string with the key dropbox_consumer_secret and the value from the Dropbox webpage.

MobileOrgNG should now compile without errors.

Short URL: http://sachachua.com/blog/p/23633

Get the highlights as a PDF!

Stories from my Twenties: Highlights from a Decade of Blogging

Free sample!