6199 comments
2357 subscribers
Follow me on Twitter (@sachac)
Subscribe! Feed reader E-mail

On this page:

How to use Emacs Org as a Basic Day Planner

So you want to use Org as day planner. I’ll show you the bare minimum that you need in order to use Org to manage your tasks day by day. I assume that you’ve set up Org and Remember according to the basic configuration suggested in “Setup.” If you haven’t done that yet, please review the section on “Setup”, then return here.

Here’s what you’ll learn how to do:

  1. Collect your tasks
  2. Schedule the tasks for specific days
  3. View your daily or weekly agenda
  4. Mark tasks as done
  5. Reschedule a task
  6. Review your accomplishments

Collecting your tasks

If you’re adding many tasks, you may find it easier to edit your Organizer file. Open ~/organizer.org in Emacs and go to the end of the file. Add headlines like this:

 * Inbox
 ** TODO your task description here
 ** TODO another task...

Instead of typing ** TODO again and again, you can use C-M-RET to create another TODO heading at the same level as the previous one. Think of all the things you need to do over the next few days and add them to your Org agenda file.

More tasks will come up as you work on things. Instead of switching to your Org agenda file each time you need to add a task, you can use C-c r t (remember, Tasks template) to remember the task quickly. Try it now by typing C-c r t. Type in the task description and press C-c C-c (org-ctrl-c-ctrl-c) to add the task to the end of the ~/organizer.org file.

Now you have plenty of tasks on your list, but no idea when you need to do that. Here’s where scheduling and deadlines come in.

Scheduling tasks

To schedule a task, move your cursor to the TODO headline and press C-c C-s (org-schedule). Org will prompt you for a date. It understands full, partial, and relative dates. For example, if today is December 29, 2007, then It understands any of the following:

Input Result Explanation
(blank) 2007-12-30 Today
10:30 2007-12-30 10:30 Time today
3:30pm 2007-12-30 15:30 Time today
31 2007-12-31 Day in the current month
12-31 2007-12-31 Month and day in the current year
2008-01-01 2008-01-01 Date
2008-01-01 12:30am 2008-01-01 00:30 Date and time (also works with partial dates)
+2 2008-12-31 Two days from now
-3 2007-12-26 Three days ago
Fri 2008-01-04 The nearest Friday (on or after today)
+2w 2008-01-12 Two weeks from today

To set a deadline for a task, type C-c C-d (org-deadline). It accepts the same kinds of date that org-schedule does.

Try this out by scheduling all of your tasks over the next few days, adding deadlines where necessary.

Now that you’ve added date information to your tasks, you probably want to see those tasks organized by date instead of in the random way you entered them. Agenda views are going to become your new best friend.

Viewing your daily or weekly agenda

Type C-c a a (org-agenda, org-agenda-list) to view your agenda. By default, Org shows a weekly view of your scheduled tasks and appointments. This is your Org agenda view.

Here are some useful navigational keys:

  • Switch to a daily view with d (org-agenda-day-view)
  • Switch to a weekly view with w (org-agenda-week-view)
  • View earlier or later days/weeks with your left and right arrow keys (org-agenda-earlier, org-agenda-later)
  • Jump to a specific day with j (org-agenda-goto-date)

Get into the habit of typing C-c a a to check your task list. It may also help to add


(org-agenda-list)

to the bottom of your ~/.emacs. This opens your Org agenda view when you start up Emacs. Start your Emacs day with your Org agenda, check it every time you finish a task, and review it before you end the day. This will help you make sure that nothing falls through the cracks.

Marking tasks as done

The easiest way to mark a task as done is to go to its line in your Org agenda view. Type C-c a a (org-agenda, org-agenda-list) to view your tasks for today, move your cursor to the task, and type t (org-agenda-todo) to cycle the task status until it’s marked DONE. You can also type C-u t (org-agenda-todo with a prefix argument) to jump to a specific task status. For example, you could type C-u t DONE to mark a task as done.

You can also mark tasks done from your ~/organizer.org file. Open the file and move your cursor to the item. Type C-c C-t (org-todo) to change the task status. Again, you can type C-u C-c C-t (org-todo) to jump to a specific task status.

I find it helpful to mark tasks as STARTED when I start working on them, WAITING if I need something else in order to continue working on the task, and DONE when I’m finished with it. That way, I can quickly see which task I was supposed to be working on before I got distracted by something bright and shiny, and I can also see what I’m waiting for. Get into the habit of doing that, and you’ll find it easier to get back on track after distractions.

Unfortunately, Org does not come with a M-x org-zap-distractions command. There will be days when you can’t do everything on your task list.

Rescheduling Tasks

You don’t have to reschedule your tasks. Org will remind you of unfinished, scheduled tasks every single day. It will even helpfully tell you how many days you’ve procrastinated on that task. If you use C-c a a (org-agenda, org-agenda-list) when you have unfinished tasks on previous days, you’ll see task reminders like this:

Saturday  29 December 2007
  organizer: Scheduled:  TODO Respond to mail
  organizer: Sched. 6x:  TODO Write notes from mentoring conversation
  organizer: Sched. 2x:  WAITING Report time

You could let your unfinished tasks snowball on you in a big mass of procrastination. If you let your task list grow to an intimidating size, though, you may start stressing out about the things you aren’t doing. Let me show you how to procrastinate—I mean, reschedule your tasks effectively—so that you can work with a more manageable task list.

If tasks are starting to accumulate, it’s a good sign that you need to review those tasks. Do you really need to do them? If not, delete them by moving to the line in your Org agenda view and pressing C-k (org-agenda-kill). You can also edit your ~/organizer.org file and delete them, but org-agenda-kill is more convenient.

If you really need to do the tasks, but there’s no point in seeing it in today’s task list because you can’t do it today anyway, use C-c C-s (org-agenda-schedule) to reschedule the task. If you’re only moving it a couple of days ahead, use S-right (org-agenda-later) to move it forward, and S-left (org-agenda-earlier) if you overshoot.

Some tasks show up again and again on your task list, and you know you need to do them, but you don’t know where to getting started. “TODO Write a book” is not a good task, because it’s just too big to do in one sitting and it doesn’t tell you what to do right now. Big tasks are often projects in disguise. Break it down into smaller tasks, and schedule those instead. If you’re in the Org agenda view, press RET (org-agenda-switch-to) to jump to the task in your ~/organizer.org file. Break it down into smaller tasks by adding sub-headings and more TODOs, like this:

 ** Write a book
 *** TODO Make an outline of what to write
 *** TODO Read sample query letters
 *** TODO Write a query letter

… and so on.

Then you can use C-c C-s (org-schedule) to schedule those tasks.

Use these commands to keep your task list manageable. That way, you get the warm and fuzzy feeling of accomplishment when you finish what’s on your list and you look at everything you’ve done today.

Reviewing your accomplishments

If you’ve been good about keeping your tasks in your ~/organizer.org file, working with your Org agenda view, and marking tasks as DONE when you finish them, you’ll find it easy (and satisfying!) to review your accomplishments. Just open your daily or weekly Org agenda view with C-c a a (org-agenda, org-agenda-list). Type l (org-agenda-log-mode) to show completed tasks. Pat yourself on the back, then plan yourself another wonderful day tomorrow!

On Technorati: , ,

Random Emacs symbol: set-fill-column – Command: Set `fill-column’ to specified argument.

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

Emacs: Getting Things Done with Org – Basic

2(please remove leading spaces from code excerpts)

You’d like to use the Org Mode for Emacs to manage your tasks. In this
blog post, I’ll cover the absolute minimum you need to get started.
We’ll assume that you already have GNU Emacs 22 and that you’re reasonably
familiar with using Emacs, including installing external modules and
adding them to your load path.

There are a million ways to plan, but we’re going to focus on two. The
first approach is Getting Things Done (GTD), described by David Allen
in the book of the same title. GTD focuses on next actions (the very
next thing you can do) and uses context lists to keep things
manageable. Popular ways to do GTD are with index cards, recycled
business cards, or software programs. If most of your tasks are in
your head or scattered on scraps of paper, GTD will probably give you
the most organizational bang for the least effort.

The second approach is day planning. You plan your week based on your
projects and priorities, write your tasks onto the pages for each day,
and copy unfinished tasks over to the next day. If you’ve used one of
those Filofax, Franklin-Covey or Dayrunner personal organizers, you’re
probably used to this way of planning.

As you learn more about Emacs and task management, you’ll probably
develop your own way of doing things. These two are a good place to
start, though. (Don’t recognize how you plan your day, but
interested in using Emacs anyway? Please get in touch with me! I may
know of something that fits, and I’d certainly love to hear about the
way you work.)

If you use GTD, read on. Otherwise, read the Setup and then wait for
the next blog post! =)

Set up

Org is part of Emacs 22. To make it even easier to collect tasks and
notes, install a separate package called Remember.

First, download and unpack Remember. As of this writing, Remember is
at version 1.9. You can get the TAR.GZ from
http://download.gna.org/remember-el/remember-1.9.tar.gz605 or the ZIP
archive from http://download.gna.org/remember-el/remember-1.9.zip606 . If
these instructions are out of date, check
http://www.emacswiki.org/cgi-bin/wiki/RememberMode607 to find out where to get Remember.

Then add this basic configuration for Org and Remember to your ~/.emacs,

   (add-to-list 'load-path "~/elisp/remember-1.9")                                  ;; (1)
   (require 'remember-autoloads)
   (setq org-remember-templates
      '(("Tasks" ?t "* TODO %?\n  %i\n  %a" "~/organizer.org")                      ;; (2)
        ("Appointments" ?a "* Appointment: %?\n%^T\n%i\n  %a" "~/organizer.org")))
   (setq remember-annotation-functions '(org-remember-annotation))
   (setq remember-handler-functions '(org-remember-handler))
   (eval-after-load 'remember
     '(add-hook 'remember-mode-hook 'org-remember-apply-template))
   (global-set-key (kbd "C-c r") 'remember)                                         ;; (3)

   (require 'org)
   (add-to-list 'auto-mode-alist '("\\.org$" . org-mode))                           ;; (4)
   (global-set-key (kbd "C-c a") 'org-agenda)                                       ;; (5)
   (setq org-todo-keywords '("TODO" "STARTED" "WAITING" "DONE"))                    ;; (6)
   (setq org-agenda-include-diary t)                                                ;; (7)
   (setq org-agenda-include-all-todo t)                                             ;; (8)
  • (1): Change the directory as necessary.
  • (2): You can use a different filename.
  • (3): You can change this keyboard shortcut.
  • (4): This tells Emacs to open all .org files in org-mode.
  • (5): You can change this keyboard shortcut.
  • (6): This makes it easy to pull in holidays and other events. See the chapter on managing your schedule.
  • (7): This includes all unfinished todos in the Org daily and weekly views. You can remove this line when you get used to working with todo lists.

After you evaluate that code by calling M-x eval-buffer or restarting Emacs, you’re ready to create an Org file.

  1. Open ~/organizer.org (or whichever file you specified in (2)).
  2. Save it. This is probably the only time you’ll have an empty TODO list.
  3. Use C-c [ (org-agenda-file-to-front) to add it to your org-agenda-files. You only need to do this once for this agenda file.

Read on to find out how to use your new Org file for GTD, or skip ahead to the section on Day Planning to find out how to plan by day!

Org and GTD

So you’ve read David Allen’s book about Getting Things Done (or any of
the countless summaries of it on the Net), and you’d like to get
started with Emacs and Org mode. I’ll show you the bare minimum you
need to support the five phases in the GTD task workflow:

Phase GTD Org
Collect Capture everything you need to do. Collect all your bits of paper or put everything into your inbox
Process Actionable? Yes: do, delegate, or defer; no: file, throw, or incubate Put tasks on your list, track delegated tasks
Organize Next actions, projects, waiting for, someday/maybe Tag tasks, view tasks by tag
Review Daily, weekly, etc. Agenda view
Do Actually do the work! No, Emacs won’t do the work for you… (But it can brew coffee!)
Collect

The first thing you need to do is get all the tasks out of your head,
off scraps of paper, out of your e-mail, and so on. If this is the
first time you’re putting tasks into Org, you have a lot of tasks to
collect. The best way to collect lots of tasks is to open your Org
agenda file (~/organizer.org) and put this heading at the end of the
file:

   * Inbox

Now go to the end of the file, and type in ** TODO and the first task
you can think of, like this:

   ** TODO Buy milk

Press C-M-RET and keep typing other tasks. Keep going until you’ve
gone through all the things in your head and all the scraps of paper
lying around. Do not get distracted. Your goal is to write all the
tasks down. If you are as easily distracted as I am, do not even open
up a browser window or look at your e-mail. It can be a real struggle
sometimes to focus long enough to get everything down, especially when
you’re writing down all these tasks that you can work on. DO NOT DO A
TASK UNLESS IT TAKES LESS THAN TWO MINUTES TO DO. In fact, if you are
just starting out with GTD, you might find it better to resist all
temptations to do tasks during this step. Get it all out.

Now that you’ve gotten your tasks out of your head and into your
organizer.org file, breathe. There’s less stress in your brain now,
because you don’t have to worry about forgetting things (as long as
you remember to check your Org file, that is!).

DO NOT FILL YOUR BRAIN BACK UP WITH OTHER THINGS TO DO. The brain is a
wonderful thing, but it’s not good at remembering what you need to do.
Whenever a task comes your way—through e-mail, in conversation, in
the shower—put it in your ~/organizer.org. Well, you probably don’t
want to drip all over the computer, so sometimes you’ll need to hang
on to an idea—but get it out of your head and into your organizer as
quickly as possible.

To collect tasks within Emacs as they come up, use Remember. With the
basic configuration you set up in the previous section, you can use
C-c r t (or M-x remember and “t” for the Tasks template) to pop up a
buffer where you can type in the task description and some notes.

    ## Filing location: Select interactively, default, or last used:
    ##     C-u C-c C-c  to select file and header location interactively.
    ##         C-c C-c  "~/notebook/personal/organizer.org" -> "* Tasks"
    ## C-u C-u C-c C-c  "???" -> "* ???"
    ## To switch templates, use `M-x org-remember'.

    * TODO

And if you’re lucky, there will even be a hyperlink to the file or
e-mail you were looking at when you called C-c r t (remember, tasks).

If you brain-dump your tasks and use C-c r t to collect tasks as they
come up, you can free up your brain for other things, such as
contemplating the meaning of life.

Process

Now that you’ve collected all those tasks into your inbox, you can
process them. Open your Org agenda file and go to your inbox.

For every item there, decide if it’s something that you need to act
on. Is it really just a note? If so, take out the TODO keyword and
organize it like you would store other notes. If it’s a true-blue
task, decide if it’s something you can do within the next two minutes,
delegate to someone else, or leave on your task list. Go through your
list systematically, delegating and eliminating whenever possible.

If you delegate the task, change it to WAITING by moving your cursor
to the headline with the TODO keyword and typing S-r (org-shiftright)
until it changes to WAITING. To keep track of who you delegated it to,
just edit the task description to reflect it. Your organizer file will
look like this:

 ** WAITING Buy milk - WJY
Organize

You have a list of tasks that _you_ need to act on. If you’ve
braindumped everything that people have asked you to do and that
you’ve thought of doing, this is probably a very long list.
Intimidatingly long. The next step in restoring sanity to your life is
to organize your list into next actions, projects, things you’re
waiting for, and someday/maybe tasks.

Review that task list. For each task, decide if it’s something you can
do immediately. Is it something you can do in one sitting, and do you
have everything you need in order to do it? If so, great! It’s a next
action. Leave it on your task list.

If you can’t immediately work on a task, it may be a project in
disguise, and it needs to be broken down into smaller, concrete next
actions. For example, the task:

 ** TODO Write a book about Emacs

would probably result in me getting complete writer’s block. If you’re
faced with a big task like this, move it out of your inbox and make it
a project. Then you can think of the very next action you need to do.
Your Org file could look something like this:

 * Projects

 ** Emacs book
 *** TODO Write about basic Org and GTD

 * Inbox

 ** TODO ... lots of other things go here ...
 ** TODO ... lots of other things go here ...
 ** TODO ... lots of other things go here ...

A task might also be stuck because you need to wait for someone else.
For example, I’m currently working on renewing my visa, but I need to
wait for the embassy. Mark those stuck tasks as WAITING with S-right
(org-shiftright).

Someday/maybe tasks are nice to think about once in a while, but you
don’t want to clutter your day-to-day tasks with them. A basic way to
deal with this is to move those tasks into a separate Organizer file
such as ~/someday.org . Another is to use tags, which we’ll cover in
the section on intermediate Org. For now, just move them to another
file.

Review

You’ve gone from a whole bunch of tasks in your brain and on pieces of
paper to one text file containing everything you need to do, with an
easy way to get to just the things you can do right now. To view all
your tasks, type C-c a t (org-agenda, tasks). You’ll get something
that looks like this:

  Global list of TODO items of type: ALL
  Available with `N r': (0)ALL (1)TODO (2)STARTED (3)WAITING (4)DONE
  TODO Write about basic Org and GTD
  TODO Blog
  TODO Answer my mail
  TODO Alter slacks
  ...

Type “1 r” to show only the active tasks, and review what you’re
waiting for with “3 r”. Review this WAITING list every so often
to make sure that nothing falls through the cracks.

Type “f” to start follow mode, which displays the relevant lines from
your Org agenda file as you move around. This is helpful for quickly
reviewing your task list.

Do

All of the above should take you less than fifteen minutes of planning
each day. The rest of the time, you can focus on doing the work,
undistracted by shiny new tasks that pop up because you can get them
out of your way with C-c r t.

To work, review your task list with either C-c a t (org-agenda, tasks)
or C-a a (org-agenda, agenda). From the agenda view, type “t”
(org-agenda-todo) to change the task status. I find it helpful to mark
a task as STARTED because it helps me remember what I was working on
in case I get distracted by something urgent, but you can also use C-u
t to jump to a status without cycling through the ones in between
(say, marking a task as DONE). You can also press ENTER to jump to the
task headline and edit it directly.

Going back to reviews: As you mark tasks done, you’ll also want to do
daily and weekly reviews. You can see those with C-c a a (org-agenda,
org-agenda-list), which opens an Org agenda view. To see completed
tasks in the Org agenda view, type l (org-agenda-log-mode). To switch
to the day view, type d (org-agenda-day-view). To switch to the week
view, type w (org-agenda-week-view). The basic configuration I’ve
suggested here will automatically include unfinished tasks at the
beginning of the agenda. Scroll up to review your tasks, and press
ENTER on a line to jump to it.

Wrapping up

There’s a lot more you can do with Org to make it support GTD, but
here’s a basic configuration that can get you started on collecting,
processing, organizing, managing, and actually doing your tasks. Stay
tuned for the intermediate Org article for more tips on setting up
repeated tasks, clocking time, working with projects, and tagging
tasks!

On Technorati: , , ,

Random Emacs symbol: bbdb-edit-current-field – Command: Edit the contents of the Insidious Big Brother Database field displayed on

UPDATE: Thanks, Victor, for catching the bug! Changed org-install to org.

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

Emacs: Choosing between Org and Planner

jaaronfarr asked me why I switched from Planner to Org. Both of them are popular personal information managers for Emacs, and both of them have practically all the features I need. They both do a good job at helping people
manage tasks, schedule, and notes. If you have a few
months to explore this, I suggest that you try both for at least a
month each. On the other hand, if you want quick results, some time
thinking about how you plan can save you more time later.

I tried out Org because I was working on a chapter about schedule
management and it wasn’t fair to just rely on the manual or the
mailing list. In the beginning, I
felt frustrated by the lack of things I’d gotten used to in Planner:
the freedom to edit anything on my day page, little conveniences like +2tue to mean two Tuesdays from now (which Carsten has just added), publishing my blog…

After two months of using Org almost every day, I’m starting to
understand it. I’ve come to appreciate the ease of working with an
outline. I love the way it clocks time. I find the daily and weekly
views really helpful. I’ve hacked stuff for it: time/load estimation,
time reporting, next action summaries, agenda publishing… I’m fairly deeply

As a geek, I have to confess—I like Planner more. Planner is more fun
to code. Maybe it’s because I’ve spent years with it, and I know my
way around the source.

Maybe it’s because we split Planner up into lots of little pieces that
can be reused and advised. Maybe the modularity of Planner is because
chunks of the code were written on a computer with a teensy screen,
which forced me to write functions that fit 80×48 characters. (See,
that limitation was there for a reason!) There are plenty of entry
points. From time to time, I still find myself copying an entire
function in order to change something in the middle, but usually I can
just get away with wrapping something around something else. With Org,
I find myself doing a lot of copy-and-paste programming. I’d fix this
by breaking the functions down into smaller bits, but I don’t have the
brainspace right now. Maybe after the book.

Org is better for my brain, though. It gives me a better overview of
both the ground-level tasks (what am I going to do right now, today,
this week) as well as the 50,000-foot view (what are my big projects)?
Planner’s good at the ground-level tasks, but the overview’s always
been a little awkward because it has to visit a number of files to get
a big picture. Org handles that easily.

And the one-place-for-data thing of Org is pretty cool, too. Org
dynamically generates reports, which could take a bit longer if you
have a large Org file. Planner copies data wherever it makes sense, so
you’d have a copy of the task on your day page and a copy of the task
on your plan page. Plan pages can get out of sync unless you’re either
religious about using planner-edit-task-description and other
functions to edit your tasks, or you use planner-id and you’re lucky.
Timeclock entries get out of sync, too. You can trust Org more than
Planner in terms of consistency.

So now I’m kinda in the middle of these two modules. I use Org for all
my work tasks, and I’m moving towards using it for all of my personal
tasks as well. But I still keep my blog entries in Planner, even
though they get mirrored into a WordPress blog on my web server.

*What would I recommend?*

It depends on the way you think. If you’re the kind of person who was
never happy with day planners because you needed more space to doodle,
write notes, move things around, add other things, try out Planner. If
you like outlines and organizing your tasks into projects, try out
Org.

Note that just because you work that way now doesn’t mean you’ll work
that way in the future. Don’t worry. Emacs will adapt. You can switch
between Planner and Org fairly easily. Just give yourself a week or so
to adjust (or a month if you’ve customized your old tool extensively
and miss lots of things about it). Use the tool every day, and you’ll
be fine.

Have you tried out both? Or have you tried out one of them and are curious about the other? I’d love to learn from your experience or answer your questions.

On Technorati: , , ,

Random Emacs symbol: malayalam-composition-function – Function: Compose Malayalam characters in REGION, or STRING if specified.

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

Bugfix: Time estimation

This is a slightly better version of sacha/org-calculate-free-time
that can understand prioritized tasks. Also, if you’re working after
midnight, it takes into account the need to sleep. That is, it doesn’t
treat _now_ as the starting point for the free-time calculation unless
it’s after the start time, so if you’re up at 12:30 writing Emacs Lisp
code, Emacs doesn’t assume you’ve got 450 extra minutes of work time.

This is what the result looks like:

Day-agenda:
Wednesday 26 December 2007
   8:00......  --------------------
  10:00......  --------------------
  12:00......  --------------------
 Scheduled:  12:00-21:00  TODO Christmas festivities with W-'s family
  14:00......  --------------------
  16:00......  --------------------
  18:00......  --------------------
  20:00......  --------------------
  22:00......  --------------------
 Scheduled:               TODO [#A] 120 Write Planner and Org comparison for tasks
 Scheduled:               TODO 30 Start on my letter for 2007
 Scheduled:               TODO 60 Respond to e-mail
 Scheduled:               TODO 30 Donate when my charity budget hits $1000
 Scheduled:               WAITING 30 Send money to Ateneo CS dept
 In 919 d.:               101 things in 1001 days
90.0% load: 270 minutes to be scheduled, 300 minutes free, 30 minutes ga

And here’s the code:

(defun sacha/org-agenda-load (match)
  "Can be included in `org-agenda-custom-commands'."
  (let ((inhibit-read-only t)
        (time (sacha/org-calculate-free-time
               ;; today
               (calendar-gregorian-from-absolute org-starting-day)
               ;; now if today AND after starting time, else start of day
               (if (= org-starting-day
                      (time-to-days (current-time)))
                   (max
                    (let* ((now (decode-time))
                           (cur-hour (nth 2 now))
                           (cur-min (nth 1 now)))
                      (+ (* cur-hour 60) cur-min))
                    (let ((start (car (elt org-agenda-time-grid 2))))
                      (+ (* (/ start 100) 60) (% start 100))))
                 (let ((start (car (elt org-agenda-time-grid 2))))
                   (+ (* (/ start 100) 60) (% start 100))))
                 ;; until the last time in my time grid
               (let ((last (car (last (elt org-agenda-time-grid 2)))))
                 (+ (* (/ last 100) 60) (% last 100))))))
    (goto-char (point-max))
    (insert (format
             "%.1f%% load: %d minutes to be scheduled, %d minutes free, %d minutes gap"
             (/ (car time) (* .01 (cdr time)))
             (car time)
             (cdr time)
             (- (cdr time) (car time))))))

(defun sacha/org-calculate-free-time (date start-time end-of-day)
  "Return a cons cell of the form (TASK-TIME . FREE-TIME) for DATE, given START-TIME and END-OF-DAY.
DATE is a list of the form (MONTH DAY YEAR).
START-TIME and END-OF-DAY are the number of minutes past midnight."
  (save-window-excursion
  (let ((files org-agenda-files)
        (total-unscheduled 0)
        (total-gap 0)
        file
        rtn
        rtnall
        entry
        (last-timestamp start-time)
        scheduled-entries)
    (while (setq file (car files))
      (catch 'nextfile
        (org-check-agenda-file file)
        (setq rtn (org-agenda-get-day-entries file date :scheduled :timestamp))
        (setq rtnall (append rtnall rtn)))
      (setq files (cdr files)))
    ;; For each item on the list
    (while (setq entry (car rtnall))
      (let ((time (get-text-property 1 'time entry)))
        (cond
         ((and time (string-match "\\([^-]+\\)-\\([^-]+\\)" time))
          (setq scheduled-entries (cons (cons
                                         (save-match-data (appt-convert-time (match-string 1 time)))
                                         (save-match-data (appt-convert-time (match-string 2 time))))
                                        scheduled-entries)))
         ((and time
               (string-match "\\([^-]+\\)\\.+" time)
               (string-match "^[A-Z]+ \\(\\[#[A-Z]\\] \\)?\\([0-9]+\\)" (get-text-property 1 'txt entry)))
          (setq scheduled-entries
                (let ((start (and (string-match "\\([^-]+\\)\\.+" time)
                                 (appt-convert-time (match-string 2 time)))))
                  (cons (cons start
                              (and (string-match "^[A-Z]+ \\(\\[#[A-Z]\\] \\)?\\([0-9]+\\)" (get-text-property 1 'txt entry))
                                   (+ start (string-to-number (match-string 2 (get-text-property 1 'txt entry))))))
                        scheduled-entries))))
         ((string-match "^[A-Z]+ \\(\\[#[A-Z]\\] \\)?\\([0-9]+\\)" (get-text-property 1 'txt entry))
          (setq total-unscheduled (+ (string-to-number
                                      (match-string 2 (get-text-property 1 'txt entry)))
                                     total-unscheduled)))))
      (setq rtnall (cdr rtnall)))
    ;; Sort the scheduled entries by time
    (setq scheduled-entries (sort scheduled-entries (lambda (a b) (< (car a) (car b)))))

    (while scheduled-entries
      (let ((start (car (car scheduled-entries)))
            (end (cdr (car scheduled-entries))))
      (cond
       ;; are we in the middle of this timeslot?
       ((and (>= last-timestamp start)
             (<= last-timestamp end))
        ;; move timestamp later, no change to time
        (setq last-timestamp end))
       ;; are we completely before this timeslot?
       ((< last-timestamp start)
        ;; add gap to total, skip to the end
        (setq total-gap (+ (- start last-timestamp) total-gap))
        (setq last-timestamp end)))
      (setq scheduled-entries (cdr scheduled-entries))))
    (if (< last-timestamp end-of-day)
        (setq total-gap (+ (- end-of-day last-timestamp) total-gap)))
    (cons total-unscheduled total-gap))))

On Technorati: ,

Random Emacs symbol: gnus-summary-display-while-building - Variable: If non-nil, show and update the summary buffer as it's being built.

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

Publishing my Org agenda to my blog

Some people like reading my task list.

No, I don’t know why, either. =)

But it’s up again, just in case you want to see it. This one is based
on Org-mode for Emacs, so it’s not the same task list that used to
show up on my Planner wiki.

Expect this to change a lot as I figure out how I want it to fit in.
The downside of using WordPress as my front-end is that it looks like
it’s going to be difficult to get the kind of day view I have with my
Planner version. How
do I get it to display future pages?

I may end up writing yet another layer on top of this… =(

Anyway, here’s my highly idiosyncratic config, just in case you want
to get started hacking this onto your system:

(defvar sacha/org-publish-agenda-directory "~/notebook/org/" "*Directory to save the published agenda to.")
(org-defkey org-agenda-mode-map  "p" 'sacha/org-publish-agenda)
(defun sacha/org-publish-agenda ()
  "Copy the agenda buffer to a file in `sacha/org-publish-agenda-directory'."
  (interactive)
  ;; Take the entire contents of the agenda and dump it into a text file labeled with the date.
  (let ((agenda (with-current-buffer org-agenda-buffer-name
                  (unless org-agenda-show-log (org-agenda-log-mode))
                  (buffer-string)))
        (filename (format-time-string "%Y-%m-%d.txt" (if org-starting-day (calendar-time-from-absolute (1+ org-starting-day) 0)
                                                       (current-time)))))
    (with-temp-buffer
      (insert agenda)
      (write-file (expand-file-name filename
                                    sacha/org-publish-agenda-directory)))))

(defun sacha/org-publish-agenda-today (interactive)
  "Publish today's agenda. Suitable for ~/.emacs, we hope."
  (let ((entry (assoc "a" org-agenda-custom-commands)))
    (if entry
        (org-run-agenda-series (nth 1 entry) (cddr entry))
      (call-interactively 'org-agenda-list))
  (sacha/org-publish-agenda)))

On Technorati: , ,

Random Emacs symbol: hack-local-variables – Function: Parse and put into effect this buffer’s local variables spec.

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

A day in a life with Org

I spend most of my day working on or near a computer: writing,
replying to e-mail, making phone calls, and so on. I use Lotus Notes
for my calendar because people need to be able to check my
availability for meetings. I use Emacs to keep track of what I need to
do, because it makes planning my day so much easier.

The first thing I do each morning is quickly go through my e-mail
looking for action items. Instead of leaving them in my mail inbox, I
create tasks for each of the items in my Org to-do list. I add notes
so that I don’t have to find the e-mails again. I also add other tasks
that come to mind. I add time estimates whenever I can.

This step is also a good time to review my personal objectives and
proactively set myself some tasks so that I can move towards them. For
example, if I want to learn more about career growth, I can’t wait for
e-mail from someone else telling me what to do. I have to think of
something to do, and build time into my day in order to do it. I put
all those tasks into my task inbox, which is just a header at the
bottom of my task list, like this:

(remove the leading space)

 * Inbox
 ** TODO ....
 ** TODO ....

Now that I’ve captured all these tasks, I review my day. What are my
appointments? What items are due today? I double-check this against
my official calendar to make sure I haven’t missed any
appointments. After I make sure that the important tasks and
appointments are there, I start filling in gaps, scheduling some of my
important-but-not-urgent tasks onto today.

After I’ve decided what to do that day, I review the rest of the
week. Does my workload look reasonable? Are there upcoming deadlines?
I try to make sure that all of my inbox items have scheduled dates. I
also review my list of waiting tasks to see if I need to follow up
with anyone.

After I’ve gotten the tasks all down and scheduled, it’s easy to
organize them under the appropriate headings. Billable tasks are filed
under the projects they belong to, and unbilled tasks are categorized
by how I need to report them and how I organize them into personal
projects. Organizing tasks into categories AFTER I schedule them means
less jumping around looking for unscheduled tasks.

This process (e-mail scan and daily and weekly overview) takes me
around 15 minutes, and helps keep me sane.

I try to keep my mornings free for creative brainstorming and heavy
lifting. Once I’ve reviewed my plans for the day and the week, I pick
a task and work on it for an hour or so. When I mark the task as
STARTED (“t” or “C-u t” from the Org agenda view), the clock
automatically starts ticking. When I mark the task as WAITING or DONE,
the clock automatically stops. Org timeclocking makes it easier for me
to report my hours at the end of each week. I can also compare the
actual times against my estimates, helping me improve my accuracy.

This process is my morning ritual: putting tasks into my Org agenda,
organizing them, reviewing and planning from my calendar, and then
getting started by working on something useful _before_ I spend time
catching up with the blogosphere or responding to my mail. It’s
complemented by my afternoon ritual of reviewing my completed tasks
with the Org agenda logbook and possibly blogging about some lessons
learned.

Here’s how you can use Org to do the same, assuming that you’ve set it
up already.

Morning ritual:

*Read your e-mail and create tasks.* Open your Org file. If it’s not yet in your Org agenda list, add it with C-c [ (org-agenda-file-to-front).

You can jump to the end of the file using M-> (end-of-buffer) and
add tasks just by typing "** TODO " and the task name. If you read
e-mail in Emacs (and there are plenty of good reasons to do so!), you
can set up Remember Mode to make it easy to create hyperlinked tasks
from mail and other sources. Use C-c C-d (org-deadline) to note
deadlines for the current task, and use C-c C-s (org-schedule) to note
when a task needs to be done on a certain date.

*Review your projects and create tasks.* Tag projects like this:

 ** Learn about career options within the company     :PROJECT:

Then you can use a custom agenda view to see your agenda for today, your projects, and other useful information.
Here's something you can add to your ~/.emacs:

(global-set-key (kbd "C-c a") 'org-agenda)
(setq org-agenda-custom-commands
      '(("a" "My custom agenda"
	 ((org-agenda-list nil nil 1)
	  (tags "PROJECT-WAITING")
	  (tags-todo "WAITING")
	  (tags-todo "-MAYBE")))))

You can then use C-c a a (org-agenda, custom command) to get an overview of your day/week, your
current projects, your WAITING tasks, and your active tasks.

*Review your day.* Use C-c a a (org-agenda, custom command) to see
your appointments for the day, and open your Org file in another
buffer. Use C-c C-s (org-schedule) in your Org file to schedule some
of your inbox tasks for the day and some of your tasks for other days
in the week. You can use Shift-right and Shift-left to reschedule
tasks from the agenda view. Use "w" in the agenda to switch to a
weekly view, and "d" to switch to a daily view.

If you want to see how your time estimates fit into your workday with
a load estimate like this:

15.8% load: 90 minutes to be scheduled, 570 minutes free, 480 minutes gap

add estimated number of minutes to your tasks like this:

** TODO 60 Browse through a book
** TODO 15 Scan my RSS feeds

and use the following code in your ~/.emacs:

(defun sacha/org-show-load ()
  "Show my unscheduled time and free time for the day."
  (interactive)
  (let ((time (sacha/org-calculate-free-time
               ;; today
               (calendar-gregorian-from-absolute (time-to-days (current-time)))
               ;; now
               (let* ((now (decode-time))
                      (cur-hour (nth 2 now))
                      (cur-min (nth 1 now)))
                 (+ (* cur-hour 60) cur-min))
               ;; until the last time in my time grid
               (let ((last (car (last (elt org-agenda-time-grid 2)))))
                 (+ (* (/ last 100) 60) (% last 100))))))
    (message "%.1f%% load: %d minutes to be scheduled, %d minutes free, %d minutes gap\n"
            (/ (car time) (* .01 (cdr time)))
            (car time)
            (cdr time)
            (- (cdr time) (car time)))))

(defun sacha/org-agenda-load (match)
  "Can be included in `org-agenda-custom-commands'."
  (let ((inhibit-read-only t)
        (time (sacha/org-calculate-free-time
               ;; today
               (calendar-gregorian-from-absolute org-starting-day)
               ;; now if today, else start of day
               (if (= org-starting-day
                      (time-to-days (current-time)))
                   (let* ((now (decode-time))
                          (cur-hour (nth 2 now))
                          (cur-min (nth 1 now)))
                     (+ (* cur-hour 60) cur-min))
                 (let ((start (car (elt org-agenda-time-grid 2))))
                   (+ (* (/ start 100) 60) (% start 100))))
                 ;; until the last time in my time grid
               (let ((last (car (last (elt org-agenda-time-grid 2)))))
                 (+ (* (/ last 100) 60) (% last 100))))))
    (goto-char (point-max))
    (insert (format
             "%.1f%% load: %d minutes to be scheduled, %d minutes free, %d minutes gap\n"
             (/ (car time) (* .01 (cdr time)))
             (car time)
             (cdr time)
             (- (cdr time) (car time))))))

(defun sacha/org-calculate-free-time (date start-time end-of-day)
  "Return a cons cell of the form (TASK-TIME . FREE-TIME) for DATE, given START-TIME and END-OF-DAY.
DATE is a list of the form (MONTH DAY YEAR).
START-TIME and END-OF-DAY are the number of minutes past midnight."
  (save-window-excursion
  (let ((files org-agenda-files)
        (total-unscheduled 0)
        (total-gap 0)
        file
        rtn
        rtnall
        entry
        (last-timestamp start-time)
        scheduled-entries)
    (while (setq file (car files))
      (catch 'nextfile
        (org-check-agenda-file file)
        (setq rtn (org-agenda-get-day-entries file date :scheduled :timestamp))
        (setq rtnall (append rtnall rtn)))
      (setq files (cdr files)))
    ;; For each item on the list
    (while (setq entry (car rtnall))
      (let ((time (get-text-property 1 'time entry)))
        (cond
         ((and time (string-match "\\([^-]+\\)-\\([^-]+\\)” time))
          (setq scheduled-entries (cons (cons
                                         (save-match-data (appt-convert-time (match-string 1 time)))
                                         (save-match-data (appt-convert-time (match-string 2 time))))
                                        scheduled-entries)))
         ((and time
               (string-match “\\([^-]+\\)\\.+” time)
               (string-match “^[A-Z]+ \\(\\[#[A-Z]\\]\\)? \\([0-9]+\\)” (get-text-property 1 ‘txt entry)))
          (setq scheduled-entries
                (let ((start (and (string-match “\\([^-]+\\)\\.+” time)
                                 (appt-convert-time (match-string 1 time)))))
                  (cons (cons start
                              (and (string-match “^[A-Z]+ \\(\\[#[A-Z]\\]\\)? \\([0-9]+\\) ” (get-text-property 1 ‘txt entry))
                                   (+ start (string-to-number (match-string 2 (get-text-property 1 ‘txt entry))))))
                        scheduled-entries))))
         ((string-match “^[A-Z]+ \\([0-9]+\\)” (get-text-property 1 ‘txt entry))
          (setq total-unscheduled (+ (string-to-number
                                      (match-string 1 (get-text-property 1 ‘txt entry)))
                                     total-unscheduled)))))
      (setq rtnall (cdr rtnall)))
    ;; Sort the scheduled entries by time
    (setq scheduled-entries (sort scheduled-entries (lambda (a b) (< (car a) (car b)))))

    (while scheduled-entries
      (let ((start (car (car scheduled-entries)))
            (end (cdr (car scheduled-entries))))
      (cond
       ;; are we in the middle of this timeslot?
       ((and (>= last-timestamp start)
             (< = last-timestamp end))
        ;; move timestamp later, no change to time
        (setq last-timestamp end))
       ;; are we completely before this timeslot?
       ((< last-timestamp start)
        ;; add gap to total, skip to the end
        (setq total-gap (+ (- start last-timestamp) total-gap))
        (setq last-timestamp end)))
      (setq scheduled-entries (cdr scheduled-entries))))
    (if (< last-timestamp end-of-day)
        (setq total-gap (+ (- end-of-day last-timestamp) total-gap)))
    (cons total-unscheduled total-gap))))

Then you can add it to your custom agenda by using this in your ~/.emacs:

;; Change your existing org-agenda-custom-commands
(setq org-agenda-custom-commands
      '(("a" "My custom agenda"
	 ((org-agenda-list nil nil 1)
          (sacha/org-agenda-load)    ; ADD THIS LINE
	  (tags "PROJECT-WAITING")
	  (tags-todo "WAITING")
	  (tags-todo "-MAYBE")))))

*Organize your inbox.* Now that you've scheduled your tasks, move them
under the appropriate headings. You can use TAB to collapse a task
into a single line, then C-k (kill-line) to cut it and C-y to paste it
elsewhere. I like using C-r (isearch-backward) to search for the right
place in the file.

*Get to work!* You may find it useful to have four states for a task: TODO, STARTED, WAITING, and DONE.
It's also handy to type in a note when you mark a task as done. To set that up, just add the following to the beginning of your Org file:

#+STARTUP: lognotedone
#+SEQ_TODO: TODO STARTED WAITING DONE

Then you can use "t" (org-todo) from the Org agenda view or C-c C-t
(org-todo) from the Org file to mark a TODO task as STARTED, or to
move from one state to the other. To move to a specific state (DONE
from STARTED, for example), either edit it directly or use C-u before
the org-todo command.

Use the following code to automatically clock in when you start a
task, start a task when you clock in, and clock out of a task when you
mark it as waiting.

(defun sacha/org-clock-in-if-starting ()
  "Clock in when the task is marked STARTED."
  (when (and (string= state "STARTED")
             (not (string= last-state state)))
    (org-clock-in)))
(add-hook 'org-after-todo-state-change-hook
	  'sacha/org-clock-in-if-starting)
(defadvice org-clock-in (after sacha activate)
  "Set this task's status to 'STARTED'."
  (org-todo "STARTED"))

(defun sacha/org-clock-out-if-waiting ()
  "Clock in when the task is marked STARTED."
  (when (and (string= state "WAITING")
             (not (string= last-state state)))
    (org-clock-out)))
(add-hook 'org-after-todo-state-change-hook
	  'sacha/org-clock-out-if-waiting)

*Review your accomplishments at the end of the day.* You can use the
Org agenda logbook to see all your completed tasks. From an Org agenda
view such as the custom one you set up for C-c a a, type "l"
(lowercase L). You can then see your completed TODOs.

To review your time usage, you can use C-c C-x C-d (org-clock-display)
from an Org buffer to see time totals according to the tree, or you
can add a table to your custom agenda view. Add the following to your
~/.emacs:

(defun sacha/org-agenda-clock (match)
  ;; Find out when today is
  (let* ((inhibit-read-only t))
    (goto-char (point-max))
    (org-dblock-write:clocktable
     `(:scope agenda
       :maxlevel 4
       :tstart ,(format-time-string "%Y-%m-%d" (calendar-time-from-absolute (1+ org-starting-day) 0))
       :tend ,(format-time-string "%Y-%m-%d" (calendar-time-from-absolute (+ org-starting-day 2) 0))))))

and then add sacha/org-agenda-clock to your custom agenda in
org-agenda-custom-commands in your ~/.emacs file, like this:

;; Change your existing org-agenda-custom-commands
(setq org-agenda-custom-commands
      '(("a" "My custom agenda"
	 ((org-agenda-list nil nil 1)
          (sacha/org-agenda-load)
          (sacha/org-agenda-clock)    ; Add this line
	  (tags "PROJECT-WAITING")
	  (tags-todo "WAITING")
	  (tags-todo "-MAYBE")))))

You can then use C-c a a (org-agenda, custom command) to see a table summarizing your clocked-in time for that day.

END RESULT: You can add tasks, quickly get an overview of your day and
week, reschedule tasks until you've got a realistic load, keep track
of your progress, and review your accomplishments.

Org keeps me sane. =) The code above only looks like a lot of customization, but it's well worth it.

Next, I'm going to figure out how to calculate my velocity, or estimated time divided by actual time taken... =)

(Thanks to Pete Bevin for catching a typo! =) )

On Technorati: , , , ,

Random Emacs symbol: floor - Function: Return the largest integer no greater than ARG.

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

Finding out if I’m overscheduled

If you’re anything like me, your task list is long and growing, but
the time you have is just as fixed. How do you manage that? I handle
that problem by looking at my calendar and my task list together when
I’m planning my day. I tend to be too optimistic about my tasks,
trying to schedule more into my day than I should. Fortunately, Emacs
can help me make sure I don’t overcommit. Here’s how it works.

When I create and schedule tasks, I try my best to add time estimates.
The numbers in the TODO headline represent minutes.

* TODO 15 Announce tea party
  SCHEDULED: <2007-12-08 Sat>
* DONE 30 Drop letters off at post office
  SCHEDULED: <2007-12-08 Sat>
* TODO 60 Write blog post about tasks
  SCHEDULED: <2007-12-08 Sat>
* TODO 60 Make book notes
  SCHEDULED: <2007-12-09 Sun>
* TODO 30 Start on my letter for 2007
  SCHEDULED: <2007-12-08 Sat>
* TODO 60 Follow up with DemoCamp contacts
  SCHEDULED: <2007-12-08 Sat>
  DEADLINE: <2007-12-09 Sun>
* TODO 60 Respond to mail
  SCHEDULED: <2007-12-08 Sat>

Then my custom agenda view looks like this:

Day-agenda:
Saturday   8 December 2007
  6:00......  --------------------
  8:00......  --------------------
 10:00......  --------------------
 12:00......  --------------------
 14:00......  --------------------
 14:00-17:15  Scheduled:  TODO Take another driving lesson - emergency stuff
 16:00......  --------------------
 18:00......  --------------------
 20:00......  --------------------
 22:00......  --------------------
              In   1 d.:  TODO 60 Follow up with DemoCamp contacts
              Scheduled:  TODO 15 Announce tea party
              Scheduled:  TODO 60 Write blog post about tasks
              Scheduled:  TODO 30 Start on my letter for 2007
              Scheduled:  TODO 60 Follow up with DemoCamp contacts
              Scheduled:  TODO 60 Respond to mail
              In 937 d.:  101 things in 1001 days
62.7% load: 225 minutes to be scheduled, 359 minutes free, 134 minutes gap

I’ll need to figure out over the next few weeks what kind of a load
threshold is good (you really don’t want to try for 100%), but at
least it’s visible!

(setq org-agenda-custom-commands
      '(("i" "My agenda"
         ((org-agenda-list nil nil 1)
          (sacha/org-load)))
        ;; ... other stuff goes here
      ))

(defun sacha/org-show-load ()
  "Show my unscheduled time and free time for the day."
  (interactive)
  (let ((time (sacha/org-calculate-free-time
               ;; today
               (calendar-gregorian-from-absolute (time-to-days (current-time)))
               ;; now
               (let* ((now (decode-time))
                      (cur-hour (nth 2 now))
                      (cur-min (nth 1 now)))
                 (+ (* cur-hour 60) cur-min))
               ;; until the last time in my time grid
               (let ((last (car (last (elt org-agenda-time-grid 2)))))
                 (+ (* (/ last 100) 60) (% last 100))))))
    (message "%.1f%% load: %d minutes to be scheduled, %d minutes free, %d minutes gap"
            (/ (car time) (* .01 (cdr time)))
            (car time)
            (cdr time)
            (- (cdr time) (car time)))))

(defun sacha/org-load (match)
  "Can be included in `org-agenda-custom-commands'."
  (let ((inhibit-read-only t)
        (time (sacha/org-calculate-free-time
               ;; today
               (calendar-gregorian-from-absolute org-starting-day)
               ;; now if today, else start of day
               (if (= org-starting-day
                      (time-to-days (current-time)))
                   (let* ((now (decode-time))
                          (cur-hour (nth 2 now))
                          (cur-min (nth 1 now)))
                     (+ (* cur-hour 60) cur-min))
                 (let ((start (car (elt org-agenda-time-grid 2))))
                   (+ (* (/ start 100) 60) (% start 100))))
                 ;; until the last time in my time grid
               (let ((last (car (last (elt org-agenda-time-grid 2)))))
                 (+ (* (/ last 100) 60) (% last 100))))))
    (goto-char (point-max))
    (insert (format
             "%.1f%% load: %d minutes to be scheduled, %d minutes free, %d minutes gap"
             (/ (car time) (* .01 (cdr time)))
             (car time)
             (cdr time)
             (- (cdr time) (car time))))))

(defun sacha/org-calculate-free-time (date start-time end-of-day)
  "Return a cons cell of the form (TASK-TIME . FREE-TIME) for DATE, given START-TIME and END-OF-DAY.
DATE is a list of the form (MONTH DAY YEAR).
START-TIME and END-OF-DAY are the number of minutes past midnight."
  (save-window-excursion
  (let ((files org-agenda-files)
        (total-unscheduled 0)
        (total-gap 0)
        file
        rtn
        rtnall
        entry
        (last-timestamp start-time)
        scheduled-entries)
    (while (setq file (car files))
      (catch 'nextfile
        (org-check-agenda-file file)
        (setq rtn (org-agenda-get-day-entries file date :scheduled :timestamp))
        (setq rtnall (append rtnall rtn)))
      (setq files (cdr files)))
    ;; For each item on the list
    (while (setq entry (car rtnall))
      (let ((time (get-text-property 1 'time entry)))
        (cond
         ((and time (string-match "\\([^-]+\\)-\\([^-]+\\)" time))
          (setq scheduled-entries (cons (cons
                                         (save-match-data (appt-convert-time (match-string 1 time)))
                                         (save-match-data (appt-convert-time (match-string 2 time))))
                                        scheduled-entries)))
         ((and time
               (string-match "\\([^-]+\\)\\.+" time)
               (string-match "^[A-Z]+ \\([0-9]+\\)" (get-text-property 1 'txt entry)))
          (setq scheduled-entries
                (let ((start (and (string-match "\\([^-]+\\)\\.+" time)
                                 (appt-convert-time (match-string 1 time)))))
                  (cons (cons start
                              (and (string-match "^[A-Z]+ \\([0-9]+\\)" (get-text-property 1 'txt entry))
                                   (+ start (string-to-number (match-string 1 (get-text-property 1 'txt entry))))))
                        scheduled-entries))))
         ((string-match "^[A-Z]+ \\([0-9]+\\)" (get-text-property 1 'txt entry))
          (setq total-unscheduled (+ (string-to-number
                                      (match-string 1 (get-text-property 1 'txt entry)))
                                     total-unscheduled)))))
      (setq rtnall (cdr rtnall)))
    ;; Sort the scheduled entries by time
    (setq scheduled-entries (sort scheduled-entries (lambda (a b) (< (car a) (car b)))))

    (while scheduled-entries
      (let ((start (car (car scheduled-entries)))
            (end (cdr (car scheduled-entries))))
      (cond
       ;; are we in the middle of this timeslot?
       ((and (>= last-timestamp start)
             (<= last-timestamp end))
        ;; move timestamp later, no change to time
        (setq last-timestamp end))
       ;; are we completely before this timeslot?
       ((< last-timestamp start)
        ;; add gap to total, skip to the end
        (setq total-gap (+ (- start last-timestamp) total-gap))
        (setq last-timestamp end)))
      (setq scheduled-entries (cdr scheduled-entries))))
    (if (< last-timestamp end-of-day)
        (setq total-gap (+ (- end-of-day last-timestamp) total-gap)))
    (cons total-unscheduled total-gap))))

On Technorati: , , ,

Random Emacs symbol: select-safe-coding-system-function – Variable: Function to call to select safe coding system for encoding a text.

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