Blog

For the English part of the blog, see Content AND Presentation.

2019-07-15 Batch Org agenda

Org-mode agenda is a notoriously complex system. It is really great from a user’s perspective, but a nightmare for a programmer wanting to tap into its generation. A long time ago I have had an idea for a productivity tool which would compute my “agenda score” (for lack of a better name), where each task not yet done would contribute to a total of some kind of “penalty” points – and more of them depending on how long the task is overdue.

However, I am probably too stupid to be able to understand what is going on under the hood of org-agenda, and I started to look for better ways. There do exist some tools which might help with that – org-super-agenda being one of them, but there are probably others. Still, I felt this is not the best way.

I decided to drop my idea (at least until I have more time and motivation to get back to it). After some time, however, I came back to org-agenda, this time from another direction. I wanted to understand some obscure parameters Org uses to customize the agenda, and decided it would be nice to be able to test the agenda in an automated way. This way, I discovered a truly hidden gem: org-batch-agenda. It is a macro that takes a string argument and generates a text-only agenda to the standard output. (Notice that it uses princ, which in particular means that all the coloring gets lost in the process. Given how complicated translating Emacs faces to ANSI codes seems to be, this is a good idea.)

It’s especially interesting that this is a macro and not a function. Head over to the Org manual to find out why, there is a good reason!

But wait, there’s more! If you want to do some programmatic operations on the agenda data, you may find the human-readable output of org-batch-agenda suboptimal. In that case, you can use its cousin org-batch-agenda-csv. It does pretty much the same thing, only the result is in the csv format. The manual even gives an example of a Perl script postprocessing this kind of output; of course, you can easily do all sorts of cool stuff with csv data. Here is an example invocation:

emacs -Q --batch --eval='(org-batch-agenda-csv "a" org-agenda-files (quote ("~/my-org-file.org")) org-agenda-span (quote day))'

Note that we use the handy special form (quote ...), which is equivalent to '..., but avoids the dreaded single quote in the Bash single-quote-delimited string. (If you need a single quote in such a circumstance, you need to say e.g. 'single'"'"'quote', which is awful.)

Now having a possibility to batch-generate a csv file with Org agenda opens a lot of possibilities. Automated agenda testing is one of them; a simple web application serving your agenda to the browser in e.g. your smartphone is another. I am sure you could think of many others. Happy hacking!

CategoryEnglish, CategoryBlog, CategoryEmacs, CategoryOrgMode

Comments on this page

2019-07-08 Pausing an Emacs keyboard macro

As I promised last week, I’d like to describe something I probably knew a long time ago, but completely forgot about.

You can pause an Emacs keyboard macro during its execution.

But wait, there’s more! During recording a macro, you can press C-x q (this means kbd-macro-query), and when the macro is run, Emacs pauses there and gives you four choices:

  • SPC or y to just continue,
  • DEL (this means “backspace”, btw) or n to skip the rest of the macro (but not subsequent repetitions – this is important when using a numerical prefix argument when calling the macro),
  • RET or q to quit this and all subsequent repetitions,
  • C-r to enter recursive edit or C-l to recenter screen.

That is already pretty cool, but there is even more than that! C-u C-x q during macro recording enters recursive edit, and that serves two purposes: firstly, you may perform some editing which will not become part of the macro, and secondly, during macro execution, you will also enter recursive edit (and the macro will resume after C-M-c).

All this is probably not something you would use every day, but it may come handy once in a while – so it may be good to remember that something like this exists. Hopefully I won’t forget about it anymore!

CategoryEnglish, CategoryBlog, CategoryEmacs

Comments on this page

2019-07-01 Syntax-aware navigation, keyboard macros, sleeping Emacs and interactive functions

Warning: today’s post is a bit of a “stream of consciousness” in that it describes several unrelated things – or rather, several things related only by the fact that I learned them while solving one particular problem.

A few days ago I had an interesting Emacs-related problem. I wanted to record and use a keyboard macro which would find a certain TeX one-parameter macro (say, \todo) and comment it out.

The tricky part was that it was not at all guaranteed that this macro would be on a line on its own, so “finding the string \todo, going to the beginning of the line and inserting a percent character” won’t work.

All is not lost, however. Emacs has the excellent and extremely useful C-M-f command (forward-sexp), which does a few useful things. First of all, when the point is on an opening parenthesis (of any kind, so also a bracket or a curly brace, for instance), it jumps to the closing one, taking possible nested parens into account. Secondly, when on a beginning of a word or a string constant, it jumps to its end.

And now the way to go is clear: what I want to record is:

  1. Search for \todo.
  2. Go back to the backslash.
  3. Activate the mark.
  4. Press C-M-f twice (or once with a prefix argument of 2).
  5. Press M-; (comment-dwim, which calls comment-region if the region is active).

That worked well, but I had one problem with it: when the next occurrence of the \todo was not visible, I felt I was losing control and I was unsure whether my macro did what it should do. (And sometimes indeed it didn’t work – when the argument of \todo had unbalanced parens, which tripped forward-sexp).

What to do? Well, my first idea was to make Emacs sleep for a second before firing C-M-f. I quickly found the sleep-for function, only to discover that it is not a command. I then sent an email to the emacs-devel mailing list, asking whether it could be good idea to make sleep-for interactive.

Well, the Emacs community did not disappoint. I learned a bit from a few answers there.

The TL;DR is that it was not a good idea. But here are the things I learnt.

First of all, nothing stops me from saying M-: (sleep-for 1) RET in my keyboard macro. Fair enough.

Then, I learned that sleep-for does not update the display anyway, so what I really needed was sit-for (which does that, and a lot more).

The next thing (and probably the most valuable of all this) was that I could attain my goal in a completely different way: what I could do is to start recording my macro with point already on the beginning of \todo, and isearch for the next occurrence at the end of the macro. Although in this particular use-case this might not be the best idea (see my comment about unbalanced parens above), this technique is a very useful thing I tend to forget about from time to time.

(In fact, it would be even better if I could include a “break” in the keyboard macro, so that Emacs would pause during its execution. It would be even better if it could then e.g. ask if I want to continue or not. Emacs being Emacs, such a feature exists. It is so cool I am going to write a separate blog post about it. This I learned from the manual, though, not from the discussion.)

The final takeaway from the thread was something that blew my mind. (Not that it is extremely useful, but still.) It turns out that I can change a function into a command without actually redefining it. Here is how it is done:

(put 'sleep-for 'interactive-form
     '(interactive "nSleep for: "))

What is going on here? It turns out that every symbol in Elisp has something called a symbol’s property list, and Emacs puts a lot of stuff for various symbols there by defaultinteractive-form is just one of about two dozen! (BTW, from a cursory read I get the impression that it might be possible to have an interactive alias for a non-interactive function. How cool is that?)

Even after about two decades of heavy use, Emacs does not stop to astonish me…

CategoryEnglish, CategoryBlog, CategoryEmacs, CategoryTeX

Comments on this page

More...