Collecting my attempts to improve at tech, art, and life

CLI Journaling in Joplin with Raku

Tags: shell second-brain

Series: [[Journaling in Joplin with Raku]]

No image 'cover-cli-journaling-in-joplin-with-raku.png'

Does any of this enlighten, entertain, or otherwise please you? Please consider a Tip. Every little bit helps!

Let’s write a couple Raku one-liners so I can journal in Joplin from the command line!

But why?

Journaling is great. Now I’m not talking about big name Bujo bullet journaling process. I mean getting a thought down quick before I lose it. Even better if I can get that thought down in a place where I can find it later.

I know there are loads of great journaling applications. And lots of great applications that support journaling generally. But I love my command line. Too many distractions in those apps.

Command line options exist. I could use one of the bazillion command line journaling tools. Okay. Maybe not a bazillion. A couple dozen, at least.

Those apps and tools are yet another interface, another set of rules. I already have Joplin handy. Besides desktop, mobile, and terminal applications, Joplin has a CLI. And an API, but I suspect I’ll get to that later.

With uncharacteristic restraint, today I choose to get better at the tools I have rather than installing a new one.

Adding a journal entry

Code Sample
    joplin use Journal && joplin edit $(date --iso=minute)
  

GNU Date — from GNU Coreutils — gets us consistent timestamps, which simplify searching and filtering. --iso produces an ISO 8601 timestamp. Very handy. By default it prints the YYYY-MM-DD version of today’s date, but you can opt for more granularity.

Code Sample
    $ date --iso=minute
2021-05-20T08:26-07:00

  

I plan to make frequent small notes, so minute feels like a good choice.

ℹ️ use Journal?

Yes, this came up. Had the Joplin terminal app open in one terminal while I added a journal entry in another terminal. Terminal app did some sort of state maintenance thing. Next thing I know I’m adding journal entries to “Nerd Notes.”

Since it doesn’t exist, joplin will ask for confirmation before creating it.

Code Sample
    $ joplin use Journal && joplin edit $(date --iso=minute)
Note does not exist: "2021-05-20T08:26-07:00". Create it? (Y/n)

  

I’m okay with the confirmation request for now. That way I have fewer moments of accidentally creating entries.

editing a journal entry

What about more of a diary?

Leave minute off the --iso argument if you prefer a tidy collection of daily pages to my big stack of notes.

Code Sample
    joplin edit $(date --iso)
  

Now you’ll be editing the single entry for today’s date.

Reading journal entries

The best review path will be via the Joplin app itself. That way you can tag and edit.

But – if you just want a quick view of recent thoughts? That is something we can do from the command line.

This next bit gets a little fancy.

Code Sample
    joplin use Journal \
  && raku -e '
    for qx{ joplin ls }.lines.sort {
      qqx{ joplin cat $_ }.subst(
        /^(<[\dT:\-]>+)/, { "# $0" }
      ).say
    }' \
  | python -m rich.markdown -
  

Let me stall for a second.

Pretty print with Rich

We already talked about joplin use Journal. Rich Markdown formats Markdown — Joplin’s default format — for rich display in a terminal. It can even run as a standalone application. I take advantage of that here to get a pretty view of my Joplin entries:

╔══════════════════════════════════════════════════════════════════════════════╗
║                            2021-05-20T08:26-07:00                            ║
╚══════════════════════════════════════════════════════════════════════════════╝


Getting an idea for a CLI journaling tool using Joplin as the backend

The logic would look something like this:

┌──────────────────────────────────────────────────────────────────────────────┐
 joplin use Journal                                                           
 joplin edit $(date --iso)                                                    
 # append "## $(date --iso=minute)"                                           
└──────────────────────────────────────────────────────────────────────────────┘

That's it, basically. There could be more functionality, such as reviewing the
log.

╔══════════════════════════════════════════════════════════════════════════════╗
║                            2021-05-21T09:00-07:00                            ║
╚══════════════════════════════════════════════════════════════════════════════╝

Alarm 07:00, stayed in bed as long as I could. Thanks to the dogs, that was 15
minutes. Oh well.

Got the Raspberry Pi 4 set up with Raspbian, and the 500GB external drive
attached. Thinking about package managers. I know Homebrew but I could maybe try
Nix. There's a post about using Nix on Debian.

╔══════════════════════════════════════════════════════════════════════════════╗
║                          2021-05-21T14:01:00-07:00                           ║
╚══════════════════════════════════════════════════════════════════════════════╝

Resuming productivity, or something like it.

╔══════════════════════════════════════════════════════════════════════════════╗
║                          2021-05-21T20:20:00-07:00                           ║
╚══════════════════════════════════════════════════════════════════════════════╝

I keep forgetting -sel clip when using xclip. Without that it doesn't go into
the easy copy buffer.

┌──────────────────────────────────────────────────────────────────────────────┐
 $ my-command | xclip -sel clip                                               
└──────────────────────────────────────────────────────────────────────────────┘

You can also use Glow if you want a standalone Markdown pretty printer. It works. Rich is already part of my toolkit, so I’ll keep using it.

Am I ready to explain myself?

Okay, I think I’ve stalled enough. That middle bit. That’s Raku.

Code Sample
    for qx{ joplin ls }.lines.sort {
  qqx{ joplin cat $_ }.subst(
    /^(<[\dT:\-]>+)/,
    { "# $0" }
  ).say
}
  

I don’t often do one-liners. We’ll have to break it down into tiny pieces.

First, we need a sorted list of journal entries.

Code Sample
    qx{ joplin ls }  # ask `joplin` to print note titles, saving the output
  .lines         # Split that output into lines, one per note
  .sort          # Sort those lines by note title
  

Things get unpredictable if I don’t sort notes myself. Joplin tends to sort notes by last activity. Thank goodness for ISO 8601, which is easily sorted:

Code Sample
    2021-05-20T08:26-07:00
2021-05-21T09:00-07:00
2021-05-21T14:01-07:00
2021-05-21T20:20-07:00
  

Next, we need to do something with each of those note titles.

Code Sample
    for qx{ joplin ls }.lines.sort { ... }
  

Well? The content of each note is important.

Code Sample
    qqx{ joplin cat $_ }
  

qqx interpolates variables before asking the system to run your command. The variable being interpolated is our old friend $_, this time around standing in for whichever of those sorted lines we reached.

Code Sample
    2021-05-20T08:26-07:00

Getting an idea for a CLI journaling tool using Joplin as the backend

The logic would look something like this:

```bash
joplin use Journal
joplin edit $(date --iso)
# append "## $(date --iso=minute)"
```

That's it, basically. There could be more functionality, such as reviewing
the log.
  

I want to print this out in the terminal. I need to massage it a little first. Even though the file is Markdown, the first line is the note’s unformatted title. It makes quick one-line notes easier.

But it also means if I want that first line to look significant, I need to do something with this:

Code Sample
    2021-05-20T08:26-07:00
  

The most obvious fix to me? Turn it into a level one Markdown header.

Code Sample
    # 2021-05-20T08:26-07:00
  

That’s a single .subst transformation.

Code Sample
    qqx{ joplin cat $_ }.subst(  # in printed note
  /^(<[\dT:\-]>+)/,          # find the first line that looks like a timestamp
  { "# $0" }                 # and turn it into a Markdown header
)
  

Okay, I got a little lazy with the regular expression. But my brain was in one-liner mode. For a full script I’d probably spell it out more clearly.

The last step is to display the transformed note contents.

Code Sample
    qqx{ joplin cat $_ }.subst(...).say
  

Or ask them to display themselves. However you want to think of it.

This whole thing would be rather clunky as a shell alias. I could add it as a function to my .bashrc.

Code Sample
    jread() {
  joplin use Journal \
    && raku -e '
      qqx{joplin cat $_}.subst(/^(<[\dT:\-]>+)/, { "# $0" }).say for qx{ joplin ls }.lines.sort
    ' \
    | python -m rich.markdown -
}
  

Then again, maybe not. This should probably be a script. Check back in a few days.

ℹ️ Oooh a cliffhanger!

I have a working script already. What I don’t have much of is unallocated time. But hopefully yes! Soon. I did some cool stuff with multi MAIN in Raku that I’m desperate to show off.