It's a whole year since I first started developing nomad! I recently made some changes that I thought were worth highlighting with a blog, so here it is!
I decided to reimplement the logic that nomad uses to parse control sequences from program output. This meant ditching a few regex sequences that were mostly created through trial and error and replacing them with something that consumes control sequences character-by-character, checking against a list of known sequences.
Now when I say "known", I mean documented by some folks who very much appreciate the importance of this weird language known as ANSI. I copied a bunch of documentation from a great resource on these sequences that can be found here: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
The code in question can be found here: https://github.com/lukebarnard1/nomad-term/blob/0fd7f1c8b60b6d319c0283a9d63fd6ee961495c6/ctlseqs.js
Essentially what it does is it takes a bunch of templates that look a bit like the documentation in the above resource:
CSI Pm m
and creates a function that will match a given input string to this particular sequence if the string is a prefix of it.
I opted to not optimise this code too much so that I could focus on being confident that the matches were valid and that the outputs were restricted. After all, sending all of your program output through one program should require a high level of scrutiny.
There are definitely some more optimisations to be made here - for example, most sequences start with a CSI (Control Sequence Initiator) of
ESC[ followed by a sequence of digits and semi-colons. One potential optimisation here could be to consume a series of characters matching
[0-9;] without even testing against any individual sequences. I'll be making these optimisations soon!
Changing the parsing of control sequences also meant changing the internal representation of them, which required changes to the (sub)terminal implementation itself. The integration tests I had written were fairly useful but it turns out they may have recorded an incorrect snapshot before, so the actual output wasn't totally useful...
I still haven't gotten around to writing my dream unit tests of "start with an empty terminal, following these control sequences expect state to have updated in this way". I'll get around to do it! I think this would be a great candidate for some test-driven development of more separate updating of different terminal state.
Let's just say there's a lot of work left over for a rainy day.
I showed nomad to my boss and he let me know that when he run nomad, it was "blocked". When he showed me what he meant it was clear that nomad was doing a poor job at giving the user an idea of how to control it! So I decided to make the controls a lot more accessible.
So there it is, a preview of the help box that follows you around when using nomad.
You got this far, why not try nomad out! Bear in mind that all of everything you type goes through nomad and everything a program sends to stdout also goes through nomad and is stored in memory. This is true of your actual terminal (e.g.
Terminal.app etc.) but they're used by the whole world.
The repo is here: https://github.com/lukebarnard1/nomad-term :)