Category Archives: geek

Making my to-do list more detailed; process versus outcome

Some time ago, I wrote some code to make it easier for me to update my web-based Quantified Awesome time logs from Org Mode in Emacs, clocking into specific tasks or quickly selecting routine tasks with a few keyboard shortcuts. I’ve been refining my/org-clock-in-and-track, my/org-clock-in-and-track-by-name, and defhydra my/quantified-hydra, and I’ve been getting used to the new workflow. The more I smooth out the workflow, the more possibilities open up. Because I’ve set it up to prompt me for a time estimate before I start a task, I can see a running clock and timer in my modeline, and Emacs lets me know if I’m running over my estimate. Come to think of it, this makes it even easier to track at the detailed task level than to track at just the medium-level categories available through my web or mobile shortcuts. (If you’re curious about the Emacs Lisp code, you can check out my Emacs configuration.)

I’ve also been sorting out my workflow for quickly adding tasks. C-c r t (org-capture, with the t template I defined in org-capture-templates) displays a buffer where I can type in the task information and set a time estimate. From there, I can file it under the appropriate project with C-c C-w (org-refile), or maybe schedule it with C-c C-s (org-schedule).

Since both creating and tracking tasks are now easier, I’ve been gradually adding small, routine tasks to my task list. This includes household tasks such as vacuuming and quick computer-based tasks such as checking for replies to @emacs. These tasks are in my routines.org file or tagged with the :routine: tag, so I can sort them in my Org agenda view or filter them out if I want.

It might be interesting to bring that data from Emacs to my mobile phone, but it’s not particularly important at the moment. I’m usually home, so I can just check my org-agenda throughout the day. If I’m out for some errands, my errand list is short enough to remember (or quickly note somewhere), and I can use my phone to quickly jot short notes to add to my to-do list when I get back.

The next step for that workflow would probably be to improve my views of unscheduled tasks, choosing new things to work on based on their time estimates, contexts, or projects. I already have a few org-agenda-custom-commands for these, although I still need to tweak them so that they feel like they make sense. Project navigation works out pretty well, though, and it’ll get better as I gradually clean up my Org files.

It feels a little odd to use my to-do list this much throughout the day, compared to the less-structured approach of deciding at each moment. The day feels less leisurely and expansive. Still, there’s a certain satisfaction in crossing things off and knowing I’m taking care of the little things. I’ll find a new balance between the number of items on my list and the time I want to use to follow the butterflies of my interest or energy. Maybe I’ll use tags or priorities to highlight energizing tasks, the dessert tasks to my vegetable tasks. (Ooh, I wonder how I can get different colours in my org-agenda.) In the meantime, I think that fleshing out my to-do list even more – capturing the little routines that might get forgotten if I get more fuzzy-brained or distracted – may help me in the long run.

I think one of the things about working with a list of small, varied tasks is that there’s less of that feeling of accomplishing a big, non-routine chunk. One way I can work around this is to pick a dessert-y project focus for the morning and finish several tasks related to it, before getting through the rest of the routine tasks. There’s also a different approach: focusing on the process instead of the outcome, cultivating the satisfaction of steady progress instead of the exhilaration of a win. If I keep on improving my workflow for managing tasks, ideas, and reviews, I think it will pay off even as circumstances change.

2015-12-04e Process versus outcome -- index card #productivity #mindset #perspective #stoicism #philosophy

2015-12-04c Preparing for steady progress -- index card #productivity #fuzzy #preparation

2015-11-30 Emacs News

Links from reddit.com/r/emacs, Hacker News, planet.emacsen.org, Youtube, the Emacs commit log, the changes to the Emacs NEWS file, and emacs-devel.

Past Emacs News round-ups

Trying out dual-booting Linux again

After a long, long time being on Windows because of Autodesk Sketchbook Pro – keeping sane with a mishmash of Cygwin and Linux virtual boxes so that I could get around the limits of Windows as a development platform, and grumbling about little things like the slow performance of git and the occasional problem with too-long file paths – I’m giving dual-booting to Linux a try again.

W-‘s good influence here: his new SSD arrived and he decided to allocate some space for dual-booting to Linux. Since we have the same hardware configuration for our laptops, I figured I’d see if the Wacom drivers Just Worked and if the sketching programs on Linux had improved since I last checked them out. Mypaint still didn’t have the selection tools I was looking for, but Krita looks like it might work for my sketches. The interface isn’t as pen-friendly as Autodesk Sketchbook Pro (which I couldn’t get going under WINE), but I might be able to get the hang of using the subset of features I actually rely on.

I had some setup issues in the beginning. The Kubuntu 15 install disk I tried crashed during setup due to a wireless-related issue. I tried ElementaryOS, but found it to be a hassle because the default Elementary theme caused Emacs to crash. (Priorities, priorities.) Frankensteining it back to a basic Ubuntu distribution by removing packages and editing files like /etc/lsb-release didn’t completely solve my problems, so I installed Kubuntu 14 instead. That seems to be working so far.

I ran into a few more issues with applications. Dropbox sync created directories but not the files within them. I’m not sure whether it was the fiddling we did with our network setup (including quite a few reboots of routers and modems) or whether Dropbox sync got fixed after I unlinked my laptop through the web interface and then reconfigured it, but at least my files are downloading now at a decent speed.

The version of Evernote I installed under WINE didn’t allow me to edit notes. Upgrading WINE to 1.7 and downgrading Evernote to 5.8.3 seems to have made Evernote work, though, so now it’s synchronizing the gazillions of notes I’ve accumulated throughout the years.

Postfix Gmail forwarding was straightforward to set up. I successfully sent a test message, and my Gnus config seems to be working fine with direct IMAP access to Gmail. I might give offlineimap a try, maybe with notmuch.

I have an old Truecrypt volume lying around, and the Linux binaries were able to mount it. Hooray!

Git was giving me problems, so I added the git-core repository.

I’ll still probably need to boot into Windows to do my business accounting in Quickbooks, which I use mainly because it imports into Turbotax and therefore saves me from having to figure out all the tax stuff by hand. I don’t do that frequently, though, so it should be okay.

I use a Python script to download Flickr metadata. Turns out the latest version of flickrapi is incompatible with it, so I downgraded flickrapi with:

sudo pip install flickrapi==1.4.5

and that worked.

It turns out it’s the little things you notice. I missed being able to use Win+number to start or switch to applications. Fortunately, the following script worked for me, once I figured out that KDE’s custom keyboard shortcuts wanted full path to the shell command: /home/sacha/bin/focus_or_launch emacs instead of using ~/bin/focus_or_launch emacs. I modified it slightly to only look at –class instead of –name.

#!/bin/bash

# NAME:         focus_or_launch
# VERSION:      0.4
# AUTHOR:       (c) 2014 Glutanimate <https://github.com/Glutanimate/>
#
# DESCRIPTION:  Focus existing app window or launch application if no
#               window found
#
#               Simplified version of a script by Henning Bekel
#               (https://bbs.archlinux.org/viewtopic.php?pid=625009#p625009)
#
# DEPENDENCIES: xdotool
#
# LICENSE:      GNU GPLv3 (http://www.gnu.de/documents/gpl-3.0.en.html)
#
# NOTICE:       THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 
#               EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 
#               PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR 
#               IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
#               AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND 
#               PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE,
#               YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
#
#               IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY 
#               COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS 
#               PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, 
#               INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE 
#               THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED 
#               INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE 
#               PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER 
#               PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
#
# USAGE:        focus_or_launch <command>
# EXAMPLE:      focus_or_launch google-chrome


############# GLOBVAR/PREP ###############

Executable="$1"
ExecutableBase="$(basename "$Executable")"
Usage="\
Usage: $(basename $0) command
E.g.:  $(basename $0) google-chrome\
"

############## USGCHECKS #################

if [[ $# -ne 1 || "$1" =~ ^(-h|--help)$ ]]; then
  echo "$Usage"
  exit 1
fi

################ MAIN ####################

MostRecentWID="$(xdotool search --class "$ExecutableBase" | tail -1 2> /dev/null)"

if [[ -z "$MostRecentWID" ]]; then
  echo "$ExecutableBase not found. Launching new window."
  "$Executable" > /dev/null 2>&1 &
  disown
else
  echo "Focusing existing instance of $ExecutableBase."
  # use brute-force approach if activating most recent WID doesn't work
  xdotool windowactivate "$MostRecentWID" 2>&1 | grep failed \
  && xdotool search --class "$ExecutableBase" windowactivate %@
fi

There are probably a few more things I’ll run into, but it’s a good start. =)

Org Mode tables and fill-in quizzes – Latin verb conjugation drills in Emacs

I was looking for a Latin verb conjugation drill similar to these ones for and nouns and pronouns. I liked the instant feedback and the ability to quickly get hints. I couldn’t find an online drill I liked, though, so I made my own with Emacs and Org. (Because… why not?)

I wrote some code that would take a table like this:

present – 1st sing. – ago / agere agO
present – 2nd sing. – ago / agere agis
present – 3rd sing. – ago / agere agit
present – 1st plu. – ago / agere agimus
present – 2nd plu. – ago / agere agitis
present – 3rd plu. – ago / agere agunt
imperfect – 1st sing. – ago / agere agEbam
imperfect – 2nd sing. – ago / agere agEbAs
imperfect – 3rd sing. – ago / agere agEbat
imperfect – 1st plu. – ago / agere agEbAmus
imperfect – 2nd plu. – ago / agere agEbAtis
imperfect – 3rd plu. – ago / agere agEbant
future – 1st sing. – ago / agere agam
future – 2nd sing. – ago / agere agEs
future – 3rd sing. – ago / agere agEt
future – 1st plu. – ago / agere agEmus
future – 2nd plu. – ago / agere agEtis
future – 3rd plu. – ago / agere agent

I can call my/make-fill-in-quiz to get a quiz buffer that looks like this. If I get stuck, ? shows me a hint in the echo area.

latin-verb-drills-0

To make it easier, I’ve left case-fold-search set to nil so that I don’t have to match the case (uppercase vowels = macrons), but I can set case-fold-search to t if I want to make sure I’ve got the macrons in the right places.

Here’s the code to display the quiz buffer.

     (require 'widget)
     (defun my/check-widget-value (widget &rest ignore)
       "Provide visual feedback for WIDGET."
       (cond
        ((string= (widget-value widget) "?")
         ;; Asking for hint
         (message "%s" (widget-get widget :correct))
         (widget-value-set widget ""))
        ;; Use string-match to obey case-fold-search 
        ((string-match 
          (concat "^"
                  (regexp-quote (widget-get widget :correct))
                  "$")
          (widget-value widget))
         (message "Correct")
         (goto-char (widget-field-start widget))
         (goto-char (line-end-position))
         (insert "✓")
         (widget-forward 1)
         )))

   (defun my/make-fill-in-quiz (&optional quiz-table)
     "Create an fill-in quiz for the Org table at point.
The Org table's first column should have the questions and the second column 
should have the answers."
     (interactive (list (org-babel-read-table)))
     (with-current-buffer (get-buffer-create "*Quiz*")
       (kill-all-local-variables)
       (let ((inhibit-read-only t))
         (erase-buffer))
       (remove-overlays)
       (mapc (lambda (row)
               (widget-insert (car row))
               (widget-insert "\t")
               (widget-create 'editable-field
                              :size 15
                              :correct (cadr row)
                              :notify 'my/check-widget-value)
               (widget-insert "\n"))    
             quiz-table)
       (widget-create 'push-button
                      :table quiz-table
                      :notify (lambda (widget &rest ignore)
                                (my/make-fill-in-quiz (widget-get widget :table))) 
                      "Reset")
       (use-local-map widget-keymap)
       (widget-setup)
       (goto-char (point-min))
       (widget-forward 1)
       (switch-to-buffer (current-buffer))))

Incidentally, I generated the table above from a larger table of Latin verb conjugations in the appendix of Wheelock’s Latin, specified like this:

#+NAME: present-indicative-active
| laudO    | moneO   | agO    | audiO   | capiO   |
| laudAs   | monEs   | agis   | audIs   | capis   |
| laudat   | monet   | agit   | audit   | capit   |
| laudAmus | monEmus | agimus | audImus | capimus |
| laudAtis | monEtis | agitis | audItis | capitis |
| laudant  | monent  | agunt  | audiunt | capiunt |

#+NAME: imperfect-indicative-active
| laudAbam   | monEbam   | agEbam   | audiEbam   | capiEbam   |
| laudAbas   | monEbas   | agEbAs   | audiEbAs   | capiEbas   |
| laudAbat   | monEbat   | agEbat   | audiEbat   | capiEbat   |
| laudAbAmus | monEbAmus | agEbAmus | audiEbAmus | capiEbAmus |
| laudAbAtis | monEbAtis | agEbAtis | audiEbAtis | capiEbAtis |
| laudAbant  | monEbant  | agEbant  | audiEbant  | capiEbant  |

#+NAME: future-indicative-active
| laudAbO    | monEbO    | agam   | audiam     | capiam     |
| laudAbis   | monEbis   | agEs   | audiEs     | capiEs     |
| laudAbit   | monEbit   | agEt   | audiet     | capiet     |
| laudAbimus | monEbimus | agEmus | audiEmus   | capiEmus   |
| laudAbitis | monEbitis | agEtis | audiEtis   | capiEtis   |
| laudAbunt  | monEbunt  | agent  | audient    | capient    |

with the code:

#+begin_src emacs-lisp :var present=present-indicative-active :var imperfect=imperfect-indicative-active :var future=future-indicative-active
  (defun my/label-latin-with-verbs (table verbs persons tense)
    (apply 'append
           (-zip-with (lambda (row person) 
                        (-zip-with (lambda (word verb)
                                     (list word (format "%s - %s - %s" tense person verb)))
                                   row verbs))
                      table (-cycle persons))))
  (apply 'append 
         (mapcar (lambda (tense)
                   (my/label-latin-with-verbs 
                    (symbol-value tense)
                    '("laudo / laudare" "moneo / monEre" "ago / agere" "audiO / audIre" "capiO / capere")
                    '("1st sing." "2nd sing." "3rd sing." "1st plu." "2nd plu." "3rd plu.")
                    (symbol-name tense)))
                 '(present imperfect future)))

#+end_src

This uses dash.el for the -zip-with and -cycle functions. There’s probably a much better way to process the lists, but I’m still getting the hang of thinking properly functionally… =)

Anyway, I’m sure it will be handy for a number of other quiz-like things. org-drill and org-drill-table will probably come in handy for flashcards, too!

2015-11-23 Emacs News

Links from reddit.com/r/emacs, Hacker News, planet.emacsen.org, Youtube, the Emacs commit log, the changes to the Emacs NEWS file, and emacs-devel

Past Emacs News round-ups

Mail with Gnus on Windows

Update 2015-11-26: fixed link to my config. Thanks, Thomas!

I use Gmail for my mail because it:

  • synchronizes with my phone, which is handy for notifications and quick replies
  • filters most of the spam for me
  • works with a few interesting extensions such as Boomerang for Gmail

However, I like the way the Gnus mail/news client in Emacs gives me a much more keyboard-friendly way to manage lots of mail, and I can even write code to partially automate some of my common operations.

I used to have my config in in ~/.gnus, but people might find it handy, so I’ve added it to my public Emacs configuration.

I like using Gmane to read mailing lists, and I use IMAP to read my Gmail.

(setq gnus-select-method '(nnnil ""))
(setq gnus-secondary-select-methods
      '((nntp "news.gmane.org")
        (nnimap "imap.gmail.com"
                (nnimap-address "imap.gmail.com")
                (nnimap-server-port 993)
                (nnimap-stream ssl)
                (nnimap-authenticator login))))

I have two-factor authentication enabled for Gmail, so I set up an app-specific password for Gnus. I have an ~/.authinfo file set up with something like:

machine imap.gmail.com login [email protected] password mysecretapppassword
machine imap.gmail.com login [email protected] password mysecretapppassword port 993
machine smtp.gmail.com login [email protected] password mysecretapppassword port 587

(I should probably get around to using GPG to automatically encrypt and decrypt this file.)

Sending e-mail on Windows was a bit of a pain. Fortunately, I eventually found something that works. I’ve configured emailrelay to accept the mail and forward it to Gmail. The server starts with this batch file:

start "emailrelay" "C:\Program Files (x86)\emailrelay\emailrelay.exe" --as-proxy smtp.gmail.com:25 --client-auth "C:/sacha/.emailrelay" --client-tls --log --pid-file "C:\Program Files (x86)\emailrelay\emailrelay.pid" --spool-dir C:\sacha\tmp\emailrelay

Sending queued mail works with this batch file:

"c:\Program Files (x86)\emailrelay\emailrelay.exe" --as-client smtp.gmail.com:587 --client-auth c:\sacha\.emailrelay --client-tls --spool-dir c:\sacha\tmp\emailrelay

I should probably get around to using --as-proxy properly, since it still seems to hold mail until I explicitly send it.

Some more config. Not sure how much of this is needed.

(setq message-send-mail-function 'smtpmail-send-it
      smtpmail-starttls-credentials '(("localhost" 25 "[email protected]" nil))
      smtpmail-auth-credentials '(("localhost" 25 "[email protected]" nil))
      smtpmail-default-smtp-server "localhost"
      smtpmail-smtp-server "localhost"
      smtpmail-smtp-service 25
      smtpmail-local-domain "local.sachachua.com")
(setq send-mail-function 'smtpmail-send-it)
(setq smtpmail-smtp-server "127.0.0.1")
(setq smtpmail-smtp-service 25)
(setq user-mail-address "[email protected]")

Hide HTML mail. I need to fiddle with this some more, since Gnus still tries to display them. Sometimes my Gnus crashes when it tries to display HTML mail.

(setq mm-discouraged-alternatives
      '("text/html" "text/richtext")
      mm-automatic-display
      (-difference mm-automatic-display '("text/html" "text/enriched" "text/richtext")))

Hide quoted text.

(setq gnus-treat-hide-citation t)

Get smarter about filtering depending on what I reed or mark. I use ! (tick) for marking threads as something that interests me.

(setq gnus-use-adaptive-scoring t)
(setq gnus-default-adaptive-score-alist
     '((gnus-unread-mark)
       (gnus-ticked-mark (subject 10))
       (gnus-killed-mark (subject -5))
       (gnus-catchup-mark (subject -1))))