Fzfm’s “todo.txt” mode
This is another of those “why are we still calling it a file manager?” things :-)
A lot more detail is in my blogpost at https://hode.gitolite.com/blog/2026-09-12-fzfm-todotxt-mode.html so I won’t repeat it here.
Here’s the main window when you run fzfm -m t (or fzfm -m todotxt), and
then hit the down-arrow key a few times:
Notice the mode indicator on the fifth line.
The extra numbers at the beginning of each entry are:
- number of days before the task is due (negative means overdue); and this is what it is sorted by. I find this easier than mentally computing date differences from today :)
- the line number of the entry within the file, so when you hit
alt-eit opens vim at that line
The preview window is where things get interesting. It shows you all the lines in the file which contain either
- the same project as the current line (e.g.,
@tech,@birthdays) - the same context as the current line (e.g.,
+amrita) - or any of the words in the current line which start with an uppercase letter (e.g. “Prof” in line 6, “July” in line 19)
It’s pretty nice to see all other birthdays when you focus on a line with the
@birthday context, for instance.
And the code…?
This is the code for initialising the mode:
case "init" set view_cmd "todo" set preview_cmd "echo {} | rg -o -w -e 'due:20..-..-..' -e '@\S+' -e '\S*\+\w\S+' -e '[A-Z]\w+' | rg -v 'rec:\+' | rg -n -w --color=always -F -f - $TODO_FILE" set preview_window "bottom" set -g fzfm_mode_keys alt-e,alt-S
This is what runs when you hit alt-e on a line, to edit the todo file at that line:
case "alt-e" # edit current or first selection echo $selection[1]|read dummy1 n dummy2 vim $TODO_FILE +$n
Oh and I forgot to mention that there’s also a quick-and-dirty “sort the file in-place by due date” feature:
case "alt-S" vim $TODO_FILE -c 'so '(printf %s\n "sort i" "sort /due:/" "g/due:/move 0" "g/due:/move 0" wq | psub) # I challenge you to do this easier in any other language :-)
That’s it. Other than boilerplate, there’re basically 9 lines of code!
The “todo” script
This is not part of fzfm. It’s my replacement for https://github.com/todotxt/todo.txt-cli/blob/master/todo.sh, which I consider useless because it can’t even sort by due date!
Here’s my “todo” script, which I only use for display. Everything else I do within vim.
#!/bin/fish function sort_by_days_left perl -MTime::Piece -e ' my $today = localtime; open(STDOUT, "|-", "env LANG=C sort -f -k1,1n -k3 | sed -e \"s/^9999/ -/\""); while (<>) { $ln = sprintf "%3d", $.; unless (/due:(20..-..-..)/) { print "9999 $ln $_"; next; } my $d2 = Time::Piece->strptime($1, "%Y-%m-%d"); my $days = int($d2->epoch/86400) - int($today->epoch/86400); printf "%4d $ln %s", $days, $_; } ' end set rgn --passthru --color=always --colors=match:style:nobold set rgb --passthru --color=always --colors=match:style:bold set l (string length (wc -l < $TODO_FILE)) # set perlexp '$x=$.++; printf "%0'$l'd ", $x' set to cat test -t 1 && set to less # perl -pe $perlexp < $TODO_FILE | sort_by_days_left < $TODO_FILE | rg $rgn --colors=match:fg:160,160,160 -e '^ *\d+ +\d+ ' | rg $rgb --colors=match:fg:red -e '\(A\).*' | rg $rgb --colors=match:fg:yellow -e '\(B\).*' | rg $rgb --colors=match:fg:green -e '\(C\).*' | rg $rgn --colors=match:fg:115,155,235 -e '\(W\).*' | rg $rgn --colors=match:fg:155,0,235 -e '\(Z\).*' | rg $rgb --colors=match:fg:cyan -e '\S+:\S+' | rg $rgn --colors=match:fg:160,0,160 -e '@\S+' | rg $rgn --colors=match:fg:225,105,0 -e '\+\S+' | $to