Day 16: flΓ’neur

One extra flΓ’neur not in frame. #mbapr

Photo of a tour group of roughly 20 people with a tour guide giving an explanation of some old white marble facade.

Went to Phone Phix and got my phone phixed. πŸ™ƒ

Got the USB-C socket cleaned. Cost a bit but the USB-C plugs are staying in place now, so I call that a win.

Love the new categories feature in Scribbles. Went back and added them to the posts on Coding Bits and Workpad. They look and feel great.

Screenshot of Scribbles post screen showing three posts, each with a different category with a different colour.

Took a while to troubleshoot why my shell script wasn’t running in Keyboard Maestro. Turns out I needed to add #!/bin/zsh -l to launch it with ZSH, with the -l switch to read my zprofile dot file.

<img src=“https://cdn.uploads.micro.blog/25293/2024/screenshot-2024-04-16-at-8.10.49am.png" width=“600” height=“310” alt=“Screenshot of a Keyboard Maestro “run shellscript” step with the hash-bang line set to /bin/zsh with the -l switch”>

Day 15: small #mbapr

A beetle with a copper shell on a tiled floor

πŸ”— The Worlds of Podcasting

On it, their producer was lamenting not having somewhere to post a link to something being spoken about. No mention of show notes because I’m not convinced “big podcast” even knows they exist.

I’ve complained about this before and I haven’t seen any improvements. It’s as if the concept of making show-notes or even a website containing the links you mention on your podcast never cross these producers minds. That it’s perfectly okay to read URLs aloud and expect people to remember. It’s such an odd phenomenon.

πŸ‘¨β€πŸ’» On the Coding Bits blog: Go Unit Test Naming Conventions

Backlog Proc: A Better JQL

Backlog Proc is a simple item backlog tracker I built for work. I’d like to link them to Jira tickets, so that I know whether a particular backlog item actually has tasks written for them, and what the status of each of those tasks are.Β  I guess these are meant to be tracked by epics, but Jira’s UI for handling such things is a mess, and I’d like to make notes that are only for my own eyes.

Anyway, I’m was using JQL to select the Jira tickets. And it worked, but the language is a bit verbose. Plus the tool I’m running the queries in, jira-cli, requires that I add the project ID along with the things like the epic or fix version.

So I’m started working on a simpler language, one that’s just a tokenised list of ticket numbers. For example, instead of writing:

project = "ABC" and key in (ABC-123 ABC-234 ABC-345)

One could just write:

ABC-123 ABC-234 ABC-345

And instead of writing:

(project = "ABC" and epicLink = "ABC-818") OR (project = "DEF" and epicLink = "DEF-222")

One could just write:

epic:(ABC-818, DEF-222)

(note here the use of OR, in that the sets are unionised; I’m not sure how this would scale for the other constructs).

Key characteristics is that the parser would be able to get the project ID from the query, instead of having the query writer (i.e. me) explicitly add it.

I can also do introspection, such as get the relevant projects, by “unparsing” the query. An advantage of controlling the parser and language. Can’t do that with JQL.

But, of-course, I can’t cover all possible bases with this language just yet, so I’ll need a way to include arbitrary JQL.. So I’ve also added a general “escape” clause to do this:

jql:"project in (bla)"

A Few Other Things

A few other things that is needed for Backlog Proc:

  • The landing screen needs to show all the active items regardless of what project they belong to. Bouncing around projects is a bit of a hassle (to be fair, I haven’t spent any time styling the screens beyond what Buffalo generated).
  • Add back ticket drafts. I enjoyed the flow of drafting all the tickets in one hit, then clicking “Publish” and seeing them come out as a fully specified Jira epic.
  • Add the notion of logs, with a “log type”. Such types can include things like “todo” (i.e thing for me to work on), “decision” (a product decision that was agreed on), and “log” (work that was done).Β 
  • A way to quickly view the tickets in Jira so I can do batch operations over them.

Seems like the signs of middle age for a Pixel phone is that the USB-C contacts lose their grippiness. I’ll have to get mine cleaned again. Finding my phone didn’t change overnight is not a great experience.

Day 14: cactus

Okay, I admit that it’s quite a stretch to call this a cactus. I do think it’s some form of succulent, or at least a plant that’s suitable for hot, dry climates, so I’m going to go with it. #mbapr

A succulent in a pot with thick, broad leaves.

Mum found a bunch of tapes of us making radio shows when we were kids. I’m digitising them now using this radio, which is the only tape player available to me. Not pictured is the Nuc running Linux, recording the audio (forgot how painful dealing with Linux audio on the command line is).

A radio and cassette player connected to a USB interface with a few cassettes in the foreground.

Day 13: page #mbapr

Page from a journal with a hand written date of 15 July 2023 in the top left in blue, and in the centre in all-caps, the handwritten phrase 'Page Intentionally Left Blank'

Tool Command Language: Macros And Blocks

More work on the tool command language (of which I need to come up with a name: I can’t use the abbreviation TCL), this time working on getting multi-line statement blocks working. As in:

echo "Here"
echo "There"

I got a little wrapped up about how I can configure the parser to recognise new-lines as statement separators. I tried this in the past with a hand rolled lexer and ended up peppering NL tokens all around the grammar. I was fearing that I needed to do something like this here. After a bit of experimentation, I think I’ve come up with a way to recognise new-lines as statement separators without making the grammar too messy. The unit tests verifying this so far seem to work.

// Excerpt of the grammar showing all the 'NL' token matches.
// These match a new-line, plus any whitespace afterwards.

type astStatements struct {
    First *astPipeline   `parser:"@@"`
    Rest  []*astPipeline `parser:"( NL+ @@ )*"`
}

type astBlock struct {
    Statements []*astStatements `parser:"LC NL? @@ NL? RC"`
}

type astScript struct {
    Statements *astStatements `parser:"NL* @@ NL*"`
}

I’m still using a stateful lexer as it may come in handy when it comes to string interpolation. Not sure if I’ll add this, but I’d like the option.

Another big addition today was macros. These are much like commands, but instead ofΒ  arguments being evaluated before being passed through to the command, they’re deferred and the command can explicitly request their evaluation whenever. I think Lisp has something similar: this is not that novel.

This was used to implement the if command, which is now working:

set x "true"
if $x {
  echo "Is true"
} else {
  echo "Is not true"
}

Of course, there are actually no operators yet, so it doesn’t really do much at the moment.

This spurred the need for blocks. which is a third large addition made today. They’re just a group of statements that are wrapped in an object type.Β  They’re “invokable” in that the statements can be executed and produce a result, but they’re also a value that can be passed around. It jells nicely with the macro approach.

Must say that I like the idea of using macros for things like if over baking it into the language. It can only add to the “embed-ability” of this, which is what I’m looking for.

Finally, I did see something interesting in the tests. I was trying the following test:

echo "Hello"
echo "World"

And I was expecting a Hello and World to be returned over two lines. But only World was being returning. Of course! Since echo is actually producing a stream and not printing anything to stdout, it would only return World.

I decided to change this. If I want to use echo to display a message, then the above script should display both Hello and World in some manner. The downside is that I don’t think I’ll be able to support constructs like this, where echo provides a source for a pipeline:

\# This can't work anymore
echo "Hello" | toUpper 

I mean, I could probably detect whether echo is connected to a pipe (the parser can give that information). But what about other commands that output something? Would they need to be treated similarly?

I think it’s probably best to leave this out for now, and have a new construct for providing literals like this to a pipe. Heck, maybe just having the string itself would be enough:

"hello" | toUpper

Anyway, that’s all for today.

Had to wake up a 3:30 AM this morning to turn something on for work. That’s… like… an HOUR before I’m usually awake. πŸ˜›

(I am a bit tired though).

Me, yesterday:

I will be cross-posing links to these blogs here. I try to post here at least once a day, and I think it’s fair game for these posts to be counted as such.

I was planning to use Echo Feed by Robb to do this, and was hoping that it wasn’t too much longer before public release. Well, I had to way, what? 18 hours? Because it just went live, and it’s exactly what I was hoping for. Awesome work, Robb.

Day 12: magic

An ATEM Mini from Blackmagic Design we have at work. It’d be nice to have more reasons to learn how to use this. #mbapr

A Blackmagic Design ATEM Mini on a wooden desk with some of the buttons on the front panel illuminated red, green and white. Cables are plugged into the back.

Making a few changes on this blog. I’ve realise that I’d prefer to write more about my day here, rather than anything around coding or projects. I do want to write about them, but they seem to clash with the day-to-day posts here.

So I’m offloading those to two separate blogs: Coding Bits which is about the trials and tribulations of writing software, and Workpad, which is about the projects I’m working on. Don’t expect professional grade writing on either one. I’m not trying to get newsletter subscriptions or anything. They’re more a place to write thoughts, ideas, or just to blow off steam. Both are hosted on Scribbles, which I feel is the perfect place for such posts: a really low pressure environment that promotes just writing the thing.

I will be cross-posing links to these blogs here. I try to post here at least once a day, and I think it’s fair game for these posts to be counted as such.

Anyway, we’ll see how it goes.

Tool Command Language

I have this idea for a tool command language. Something similar to TCL, in that it’s chiefly designed to be used as an embedded scripting language and chiefly in an interactive context.

It’s been an idea I’ve been having in my mind for a while, but I’ve got the perfect use case for it. I’ve got a tool at work I use to do occasional admin tasks. At the moment it’s implemented as a CLI tool, and it works. But the biggest downside is that it needs to form connections to the cluster to call internal service methods, and it always take a few seconds to do so. I’d like to be able to use it to automate certain actions, but this delay would make doing so a real hassle.

Some other properties that I’m thinking off:

  • It should be able to support structured data, similar to how Lisp works
  • It should be able to support something similar to pipes, similar to how the shell and Go’s template language works.

Some of the trade-offs that come of it:

  • It doesn’t have to be fast. In fact, it can be slow so long as the work embedding and operating it can be fast.
  • It may not be completely featureful. I’ll go over the features I’m thinking of below, but I say upfront that you’re not going to be building any cloud services with this. Administering cloud servers, maybe; but leave the real programs to a real language.

Some Notes On The Design

The basic concept is the statement. A statement consists of a command, and zero or more arguments. If you’ve used a shell before, then you can imagine how this’ll look:

firstarg "hello, world"
--> hello, world

Each statement produces a result. Here, the theoretical firstarg will return the first argument it receives, which will be the string "hello, world"

Statements are separated by new-lines or semicolons. In such a sequence, the return value of the last argument is returned:

firstarg "hello" ; firstarg "world"
--> world

I’m hoping to have a similar approach to how Go works, in that semicolons will be needed if multiple statements share a line, but will otherwise be unnecessary. I’m using the Participal parser library for this, and I’ll need to know how I can configure the scanner to do this (or even if using the scanner is the right way to go).

The return value of statements can be used as the arguments of other statements by wrapping them in parenthesis:

echo (firstarg "hello") " world"
--> hello world

This is taken directly from TCL, except that TCL uses the square brackets. I’m reserving the square brackets for data structures, but the parenthesis are free. It also gives it a bit of a Lisp feel.

Pipelines

Another way for commands to consume the output of other commands is to build pipelines. This is done using the pipe | character:

echo "hello" | toUpper
--> HELLO

Pipeline sources, that is the command on the left-most side, can be either commands that produce a single result, or a command that produces a “stream”. Both are objects, and there’s nothing inherently special about a stream, other than there some handling when used as a pipeline. Streams are also designed to be consumed once.

For example, one can consider a command which can read a file and produce a stream of the contents:

cat "taleOfTwoCities.txt"
--> It was the best of times,
--> it was the worst of times,
--> …

Not every command is “pipe savvy”. For example, piping the result of a pipeline to echo will discard it:

echo "hello" | toUpper | echo "no me"
--> no me

Of course, this may differ based on how the builtins are implemented.

Variables

Variables are treated much like TCL and shell, in that referencing them is done using the dollar sign:

set name "josh"
--> "Josh"
echo "My name is " $name
--> "My name is Josh"

Not sure how streams will be handled with variables but I’m wondering if they should be condensed down to a list.Β  I don’t like the idea of assigning a stream to a variable, as streams are only consumed once, and I feel like some confusion will come of it if I were to allow this.

Maybe I can take the Perl approach and use a different variable “context”, where you have a variable with a @ prefix which will reference a stream.

set file (cat "eg.text")

echo @file
\# Echo will consume file as a stream

echo $file
\# Echo will consume file as a list

The difference is subtle but may be useful. I’ll look out for instances where this would be used.

Attempting to reference an unset variable will result in an error. This may also change.

Other Ideas

That’s pretty much what I have at the moment. I do have some other ideas, which I’ll document below.

Structured Data Support: Think lists and hashes. This language is to be used with structured data, so I think it’s important that the language supports this natively. This is unlike TCL which principally works with strings and the notion of lists feels a bit tacked on to some extent.

Both lists and hashes are created using square brackets:

\# Lists. Not sure if they'll have commas or not
set l [1 2 3 $four (echo "5")]

\# Maps
set m [a:1 "b":2 "see":(echo "3") (echo "dee"):$four]

Blocks: Yep, containers for a groups of statements. This will be used for control flow, as well as for definition of functions:

set x 4
if (eq $x 4) {
  echo "X == 4"
} else {
  echo "X != 4"
}

foreach [1 2 3] { |x|
  echo $x
}

Here the blocks are just another object type, like strings and stream, and both if and foreach are regular commands which will accept a block as an argument. In fact, it would be theoretically possible to write an if statement this way (not sure if I’ll allow setting variables to blocks):

set thenPart {
  echo "X == 4"
}

if (eq $x 4) $thenPart

The block execution will exist in a context, which will control whether a new stack frame will be used. Here the if statement will simply use the existing frame, but a block used in a new function can push a new frame, with a new set of variables:

proc myMethod { |x|
  echo $x
}

myMethod "Hello"
--> "Hello

Also note the use of |x| at the start of the block.Β  This is used to declare bindable variables, such as function arguments or for loop variables.Β  This will be defined as part of the grammar, and be a property of the block.

Anyway, that’s the current idea.

Buffalo, the Go framework that’s a bit like Rails, has been archived on GitHub. I’m wondering if it’s been retired. I’ve seen no announcement but I’m starting to suspect that it has.

A real shame. It was pretty good and the dev was so passionate behind it. Maybe running it was just too much.

Anyone looking for a really polished YouTube channel about the history of PCs and game consoles from the 70s to the early 2000s (think Apple, Commodore, MOS, Nintendo, etc.), I can recommend LowSpecGamer. They’re also on Nebula. In fact, their videos is why I signed up there yesterday. πŸ“Ί