Listing shortlog files chronologically with LaunchBar
Building on my introductory post about maintaining “shortlog” diary files, I quite often want to have a look at recent shortlog files.
I have my shortlog folder indexed by LaunchBar, so I can browse the files that way. By default these are listed in lexicographically ascending order. You can reverse this by holding down command when navigating into the folder in LaunchBar.
However, that doesn’t resolve the problem that it’s not always easy to realise that 2020-04-13 is “Monday”.
So I thought I would write a LaunchBar action to do both.
Despite being my first, it was really very easy. I wrote it in JavaScript as the documentation leads you that way, and you don’t have to serialise to JSON and write to stdout to return values. LaunchBar provides some additional tools to make interacting with the system straightforward from JavaScript. (And, to be clear, this isn’t JXA either.)
Here are the settings in the scripts pane in LaunchBar’s Action Editor:
This is a default script, taking no input. One thing to note is that it returns a result of type “Item” — an array of JavaScript objects with particular keys. You can read about the properties items can have in the LaunchBar action developer documentation.
And here’s the code:
1function run(argument) {
2 const shortlogDir = "~/Dropbox/notes/shortlog/"
3 return File.getDirectoryContents(
4 shortlogDir
5 ).filter(fileName =>
6 /^shortlog-20\d{2}-\d{2}-\d{2}.txt$/.test(fileName)
7 ).map(fileName => {
8 const isoString = fileName.substring(9, 19)
9 const dateString = LaunchBar.formatDate(
10 new Date(isoString),
11 {
12 timeStyle: "none",
13 dateStyle: "full",
14 relativeDateFormatting: true
15 }
16 )
17 return {
18 title: dateString,
19 path: shortlogDir + fileName,
20 /* Use the ISO string as LaunchBar rejects returned objects
21 containing types other than strings, numbers, arrays
22 and objects (dictionaries) */
23 date: isoString
24 }
25 }).sort(
26 /* Note this is a string comparison, but it’s OK as
27 we’re comparing ISO date strings. */
28 (first, second) => first.date > second.date ? -1 : 1
29 )
30}
This is just a “default script”, and while run
takes an argument, it’s ignored.
We treat this as a simple pipeline of transformations on data:
- reading the contents of a directory (lines 3 & 4)
- keeping only those whose filenames match dated shortlog files (lines 5 & 6)
- creating an object containing a human-readable date, the path to the file, and an ISO-format date string (lines 7–24)
- sorting those objects on the ISO date string, newest to oldest (lines 25–29).
In line 3, we make use of the File
object, which is provided by LaunchBar. And in lines 9–12 we use the formatDate
function on the LaunchBar
object, which gives us access to the system’s date formatting, which is both locale-aware and respects the user’s date & time preferences.
By providing the path in the result object, LaunchBar treats each entry in the list as a file, so you can press return to open it, or press the right arrow to inspect its details.
One oddity: I did try to store a JavaScript Date
in the result objects, to use in the final sorting, but LaunchBar displays an error if a Date
in the returned items. You could strip out any of your custom properties, but here I just use the ISO-format date string from the filename as it works just as well for the sorting comparison.
(Another oddity: I initially created the Date
(now in line 10) manually with the date components extracted from the ISO-format date string. I learned that the constructor doesn’t take a month
argument but instead a monthIndex
, in the range 0–11. Some background on why this is.)