As I mentioned a lot of times, I use Org-mode clocking all the time. Among others, I integrated it with two external services, I have a few dedicated keybindings to it in my Org-mode hydra. It’s no wonder that I work hard to make clocking as smooth as possible.
I used to have the variable org-clock-mode-line-total
set to 'today
. This means that the clock info in my modeline reflects the time I spent on this particular task, well, today. (This fits nicely in my Beeminder workflow, where I set daily goals for various stuff, measured in minutes).
However, I’m also working on my productivity, and I was toying with the idea of using the famous pomodoro technique. The main idea is that you work in 25-minute intervals with 5-minute breaks.
While I do not like the rigidity of that scheme, the idea appeals to me. There are a few Emacs-based solutions (and even one or two Org-mode ones), but none of them really resonates with me. I will definitely look into integrating some kind of timeboxing technique into my workflow in the future, but for now, I settled for a minimalist solution.
The idea is that both 'today
and 'current
are reasonable values of org-clock-mode-line-total
for me, and hence I’d like to be able to switch between them seamlessly. This way, I could either easily see how much time I spent on the currently clocked task in this particular “timebox”, or how much I spent on it today. (Having that, I decided that seeing how much I spent on it altogether can also be useful.) Since I already have my Org-mode related hydra, I decided to add one more command to it: toggle-org-clock-mode-line-total-setting
. The idea is to be able to cycle between various settings of org-clock-mode-line-total
with a keystroke.
So, I started with this:
(setq org-clock-mode-line-total-settings '((current . "time spent in this chunk on the current task") (today . "time spent today on the current task") (all . "total time spent on the current task"))) (setq org-clock-mode-line-total-setting-number 0)
This is a very rudimentary implementation of a “ring”. A ring is just like a list, only when we want to go past the last element, we get at the first again. Actually, Emacs provides a “ring” package which implements such a data structure efficiently, but I decided that it would be an overkill for just three elements – here, the simplicity of the code won over the efficiency. (In fact, after looking into the “ring” package, I’m no longer sure whether my code is really that simple… I had to do the modulo wrapping by hand, for instance – Emacs’ “ring” does that for me.)
Now, let us implement the actual cycling. This proved (quite unexpectedly) to be the hard part, since just toggling org-clock-mode-line-total
did not do the trick – somehow, I had to make Emacs recount the time of the current clocking item elapsed from the first clocking entry or just for today or the current entry.
(defun toggle-org-clock-mode-line-total-setting (setting-number) "Toggle between org-clock-mode-line-total settings. With a numeric argument, use setting SETTING-NUMBER." (interactive "P") (if (numberp setting-number) (setq org-clock-mode-line-total-setting-number (mod setting-number (length org-clock-mode-line-total-settings))) (setq org-clock-mode-line-total-setting-number (mod (1+ org-clock-mode-line-total-setting-number) (length org-clock-mode-line-total-settings)))) (let ((org-clock-mode-line-total-setting (nth org-clock-mode-line-total-setting-number org-clock-mode-line-total-settings))) (setq org-clock-mode-line-total (car org-clock-mode-line-total-setting)) (when (org-clocking-p) (setq org-clock-total-time (with-current-buffer (marker-buffer org-clock-hd-marker) (save-excursion (goto-char org-clock-hd-marker) (org-clock-sum-current-item (org-clock-get-sum-start))))) (org-clock-update-mode-line)) (message "Modeline shows %s." (cdr org-clock-mode-line-total-setting))))
The tricky thing is the latter part of the above code. Just changing the value of org-clock-mode-line-total
in the middle of clocking does not have any effect – even if we actually call org-clock-update-mode-line
. What we need to do is to call org-clock-get-sum-start
, which (as Nick Dokos pointed to me) is the only place in the Org-mode sources where our variable is used. Mimicking its use in org-clock-in
, I set the global variable org-clock-total-time
and only then call org-clock-update-mode-line
. This function calls org-clock-get-clock-string
, which calls org-clock-get-clocked-time
, which uses org-clock-total-time
and adds the currently clocked time to its value.
Elementary, my dear Watson.
The moral of this story is that while Org-mode source code is sometimes a big mess, you can still do nice things if you are patient enough and can use grep (or ask wise people than can use it).
CategoryEnglish, CategoryBlog, CategoryEmacs, CategoryOrgMode