In this post, I’ll describe one approach to running programs written in Go against text in the IDEA editor. This same approach applies to any Jetbrains IDE, such as PyCharm or WebStorm.
Admittedly, this is niche.
Tracking time at work
Number 1: Every few weeks, I need to submit a virtual time card. If I work over 40 hours, I need to note that for comp time. If I work under 40 hours, I need to fill it in with PTO.
Number 2: I work on several projects, and I need to track what percentage of my time I devote to those projects. This isn’t for a boss or paperwork: this is for me. I compare the percent of time I know I’m supposed to work on a project with the amount of time I actually spend, and I adjust accordingly.
Solving both of these problems hinges on tracking time accurately. If I have an accurate record of my time, then I can update a spreadsheet at the end of the day that keeps track of percent time spent on each project and also shows total hours each day, with a weekly summary. With that weekly summary, updating a time card website is trivial. Consequently, the ease of solving these problems directly correlates with the ease of updating the spreadsheet.
At the end of the week, the spreadsheet looks like this:
Unfortunately, counting up time spent on each project at the end of the day, and then updating the spreadsheet, is annoying and time-consuming and I’d prefer not to do it. That’s where Go comes in.
How I track time
I rather obsessively track, to about 15 minutes of granularity, what I work on, slotting the tasks into predefined categories (projects).
When I’m not on the phone or in meetings, I spend the rest of my day either in a terminal or some Jetbrains IDE. Since I spend a lot of time in an IDE, that’s the natural place for me to track time.
At the start of each day, I roughly plan the day. This is typically aspirational, but at least it’s a guide to help me visualize how I’ll spend my time. On my file system, I have a directory called “memory_hole” where I keep personal stuff like this, and I have a single file called “where_the_time_goes.md”. If Intellij is open, that file is open, and I use it to guide my weeks and days. Yes… I track my time in markdown.
A block of time looks something like this after planning the day:
- 615 - 645: RM: respond to last night's emails - 8 - 915: RM: Prep for presentation - 915 - 930: CFG: Standup - 930 - 1130: RM: Start FAQ - 1 - 4: CFG: Pick a bug and fix it - 4 - 415: CFG: submit CR for deploy user
The format is:
- from_time - to_time: category_abbreviation: details
As I work throughout the day, the times change, things drop off, things get added… how life works. At the end of the day, I have a final list that shows what time was spent on which categories. It looks exactly like the markdown list above, except that it is final and accurate for that day.
How I use Go to tally time
I wrote a Go program named sumday that takes as its input a block of text like the one described above and returns a map, keyed on category, of time spent on that category. Its output is trivial. For the above chunk of time, it will emit:
With that map, I can then go update my spreadsheet, finding each corresponding category and plopping in the number.
Still, that’s tedious. And also: how do I even feed that chunk of time into the program in the first place?
The solution: Clipboard!
If I can get that block of time onto the system clipboard, then I can run sumday, have it read the system clipboard for its input, and it can do its thing. That simply means highlighting a block of text in my editor, copying it, and then going to a shell and running sumday and then looking at its output.
Still, it’s annoying to read the map that sumday emits and then go plug in the numbers into the spreadsheet. Consequently, I use the clipboard package to have sumday emit a string, onto the clipboard, formatted in such a way that I can just put my cursor into a single spreadsheet cell (see screenshot above), hit paste, and populate the entire row.
Bottom line: in my editor, I can highlight the block of time, copy it to clipboard, run sumday in a shell, and then go back to Excel and paste in the string that sumday stuck back onto the clipboard. It’s a lot of moving around, though it only takes a few seconds in practice.
Still, it can be better.
How I wire this into Intellij
Since the block of text is in Intellij, it’d be nice to simply highlight it and then somehow run sumday right from within Intellij, via a keyboard shortcut, such that I can cut out the middle-man steps of copying text and then running sumday in a shell.
This involves 3 steps:
- Create a new External Tool that points to sumday
- Create a macro that copies whatever chunk of text is selected in the editor and runs that External Tool
- Assign a keyboard shortcut to that macro
This 3-step process is nearly identical to the one describing how to run goimports on file save and so I won’t repeat it here.
With all this in place, at the end of the day I simply highlight my block of time, hit my key combo (splat-alt-S), and then go paste the clipboard into the spreadsheet.
This all started with an annoying problem and a desire to solve it, though all of this might seem like building a faster horse (or a process that should be taken out back and shot!). I’ve tried a few online time tracking apps, but none so far have suited me. (yeah yeah, I know… time tracking in markdown… get off my lawn). If you have a preferred time tracking app with support for categories, weekly rollups, percent-time-per-category, please let me know about it.
I used Go because that’s the language I’m learning at the moment and I quite enjoy programming in it. I wired it into Intellij because it was logical to do so.
With this one program, in addition to solving a problem, I learned:
- Go’s excellent Duration type
- Ginkgo and Gomega for BDD in Go
- How to use clipboard to bus stuff back and forth between the IDE and a Go program