While this last week was my first week back full-time, I've been working intermittently on a major refactor throughout the holidays. I'll make a post on my personal blog with the gory technical details once the work is done, but for now I wanted to provide a small update with an explanation of what I'm doing and why.

Releases over the past month

Most of my work hasn't been user-facing and so hasn't merited notes in the changelog, but I wanted to make a note of it anyhow.

  • Fixed wording of a bunch of spells (5e-database#435)

  • Corrected a bunch more spells and added/fixed missing data tables (5e-database#437)

  • Macro-ified parse and autocomplete logic for most of the simpler command cases:

    • app commands (help, roll d20)

    • reference commands (Fireball, weapons)

    • time commands (+30m, time)

    • storage commands (journal, save)

  • Updated the Marked library to the latest version (technically a security update, though initiative.sh was unaffected)

This week

Effectively, the process for parsing input as well as generating autocomplete suggestions had reached a breaking point. Every time I wanted to add a new feature, the feature itself would take a day to implement, followed by another day to implement the parser, and three more days to get the autocomplete working the way I wanted it to and get the whole thing adequately tested. A cursory glance finds 419 lines of code dedicated to parsing and 917 lines for autocomplete, not including tests, scattered across various files and specially crafted for every possible input (twice, once for parse and once for autocomplete).

Fortunately, I have an alternative: instead of writing the code by hand, I can write code to generate the code that I would have written by hand. Moreover, by doing the generation in one place, everything should be easier to test and reason about. And by removing the need to duplicate code, I'll make everything faster and more reliable with fewer lines of code, right?

The current status of this operation is 6,279 lines of code added, 3,412 lines deleted.

However, while I've been periodically pausing to re-evaluate whether this work is worthwhile, I think the answer is still a begrudging "yes". Being able to declare that a command exists and trust the compiler to make it so will be hugely valuable. And while there are libraries that could do some of this, I haven't found anything that works well for my specific use case:

  • Permissively parsing word phrases (not strings of bytes)

  • Providing suggestions via autocomplete

  • Dynamically updating suggestions based on things that exist (eg. names from the journal)

  • Intelligently resolving ambiguities (eg. try creating a character named Open Game License)

  • Representing the parsed output in a format that then doesn't need to be re-parsed to be runnable

I can see parts of this work being valuable as an open-source crate, but its integration with the rest of the application is currently tight enough that I can't easily unbundle it at the moment. That might be a job for a future iteration, once this is in more workable form.

Until then, I plod on.