Over christmas I decided it would be fun to learn Rust, a (somewhat) new systems-ish language championed by Mozilla (Keep in mind the last time I used C, or really any systems language, was in 2006). Instead of jumping straight into a crazy custom stack project or something that would never get finished I decided to write a pretty simple tool I’ve been thinking about for quite a while.

No, it’s not a REST service, some Github integration, or an iOS application, it has nothing nothing to do with the cloud or data science…? Nope the result of my efforts is a cross platform (Linux/Darwin and you can probably build it on Windows but I haven’t tried…) CLI note taking tool called theca (the name comes from a Greek compendium of myths and legends titled The Bibliotheca), how exciting! Now there is no real reason for theca to be written in Rust, in fact most of the codebase could probably be written in half the LOCs by using an OO-language, but where is the fun in that?! and hey memo is written in C (plus just writing Python all the time can get pretty boring…) While some of the code is still rather dirty, and liable to change in the future, I haven’t changed the external functionality for quite a while and have a no plans for any new features so I decided now was good enough a time as any to release it to the world.

View project on GitHub

This post will be a relatively quick roundup of some of the things you can do with theca but I won’t cover everything. For a full (quite, very long) usage guide (with lots and lots of screenshots) as well as the TODO items etc check out the README.md file in the Github repo.

So what does theca do? Well it’s pretty simple, it takes notes! Beyond that here is a cursory list of features

  • easy note profile management
  • plaintext or 256-bit AES encrypted profiles
  • easily synchronizable profiles
  • edit notes using CLI editor (set via $VISUAL or $EDITOR)
  • transfer notes between profiles simply
  • plaintext or JSON output modes
  • search notes by keyword or regex pattern
  • simple external integration

And what are these profiles you speak of? theca utilizes what I call profiles which are, basically, just individual JSON files containing the notes for that profile and a flag indicating if the profile is encrypted. By default theca will look for profiles in either ~/.theca or the folder set in THECA_PROFILE_FOLDER and will then read either the default profile file default.json, the default profile file for the profile set in THECA_DEFAULT_PROFILE, or the profile file for the profile secified by -p PROFILE. Profile files follow the extremely simple naming scheme name.json.

Profiles are essentially used to segregate notes based on whatever reasoning you choose e.g. work, dev, secrets, thoughts-about-squids, diary, etc etc and can be either plaintext or encrypted.

Getting theca

There are two (well three) ways to get theca

  1. Get the precompiled nightly binaries

    I currently build and package nightly binaries (if anything in the repo has changed, and both of my laptops are on the same network, and I’m awake…) for x86_64-unknown-linux-gnu, i686-unknown-linux-gnu, x86_64-apple-darwin, and i686-apple-darwin that you can download and install using the packaged install.sh script or by using the hosted get_theca.sh script. Nightly (and in the future stable) packages are currently hosted here https://static.bracewel.net/theca/dist/ and can be somewhat unstable (previous nightlies are stored in subdirectories by date if the current nightly doesn’t work for some reason, eg. /theca/dist/theca-nightly-2015-02-13/ contains the very first packaged binaries I uploaded).

    a. Download and install manually

     # Choose the right architecture and platform and download from static.bracewel.net
     $ wget https://static.bracewel.net/theca/dist/theca-nightly-x86_64-unknown-linux-gnu.tar.gz
     ...
        
     $ tar vxzf theca-nightly-x86_64-unknown-linux-gnu.tar.gz
     ...
        
     $ cd theca-nightly-x86_64-unknown-linux-gnu
     $ ./install.sh
     ...
    

    b. Install using curl and get_theca.sh

     $ curl -s https://static.bracewel.net/theca/get_theca.sh | sh
    

    Currently get_theca.sh will download the most recent nightly package, but once I’ve released the first stable version of theca (1.0.0-stable) it will switch to automatically downloading and installing that package, at that point I’ll also add a --nightly flag which will allow you to revert get_theca.sh to the current behavior and download/install the most recent nightly.

    Some people may be (understandably) uncomfortable piping random scripts into curl, so I’d suggest you check out the two-stage installation process get_theca.sh uses (in get_theca.sh and package-installer.sh which is named install.sh in the packages) to calm your mind about what it is actually doing or build directly from the source hosted on Github

    You can also use the get_theca.sh script to uninstall theca if you wish that it no longer sullied your system

     $ curl -s https://static.bracewel.net/theca/get_theca.sh | sh -s -- --uninstall
    
  2. Build the binary from source

    If you want to build from source you’ll probably want to get the latest nightlies of rustc and cargo, these can be easily acquired by running (or again mangually install the binaries or build from source) or using multirust or whatever

     $ curl -s https://static.rust-lang.org/rustup.sh | sh
    

    Building is then as easy as

     $ git clone https://github.com/rolandshoemaker/theca.git && cd theca
     ...
    
     $ ./build.sh build [--release]
     ...
    
     $ sudo bash tools/build.sh install [--release, --man, --bash-complete, --zsh-complete]
     ...
    

    You should refer to the README in the github repo for what these flags do, but what most of them do should be fairly obvious.

Using theca

The available commands are relatively straight forward but lets quickly run through them

  • add - adds a note
  • edit - edits a note
  • del - delete single/multiple notes
  • search - searches notes by title/body using keyword/regex
  • <id> - displays note by id
  • new-profile - creates a new profile
  • list-profiles - lists all profiles in the current profile folder
  • encrypt-profile - encrypts the current profile
  • decrypt-profile - decrypts the current profile
  • transfer - transfers a note from the current profile to another
  • import - imports a note to the current profile from another

If no command is passed theca will by default list all the notes in the current profile. For more information about required/optional arguments for each command can be found by running theca --help, man theca, or reading the README.md file in the github repo.

A quick note on statuses and tags

Statuses are basically an extremely simple way of indicating the current status of a note (…yup pretty complicated) that takes the place of a more complex tagging system.

During initial development of theca I spent quite a bit of time trying to figure out which statuses I should include (or if I should allow completely custom statuses or none at all) and after playing with quite a few I ended up realising I only ever used three (well… two, if that).

  • No status at all (-n or --none, the default option for new notes)
  • Started (-s or --started)
  • Urgent (-u or --urgent)

These flags can be used when adding notes, editing notes, searching notes, and listing notes to either specify the status of the note or to filter lists by status. Tags can be replicated quite simply by prepending or appending a tag(…) to a note, as such theca add "(THECA) something about theca", and then you can do a keyword search for (THECA) to get all notes tagged as such.

Now back to how to use theca.

Lets add a bunch of notes to our default profile! (I’ve omitted it in the screenshot but you can also use the --editor flag to drop to the editor set/edit in either VISUAL or EDITOR to set the note body, but there is a gif at the end of this section of it in action)

Now lets view some notes, maybe do a search? If you don’t specify any command with theca it will list all the notes in the current profile, this can be reversed (-r or --reverse), sorted by the last time it was edited (d or --datesort), limited to a certain number of notes (-l 5 or --limit 5), or outputed as JSON(-j or --json).

By the way, there are two formats theca will use when printing most data, expanded mode (default) or condensed mode (-c flag). Condensed mode is a much more efficient way of printing out notes but its quite stripped down and can take a bit to get used to. In either mode if a note has an attached body the title will be prepended with (+).

Edit some notes?

And finally delete a bunch of notes.

Bonus --editor gif

Line formatter

theca containers a relatively simple lineformatter that is used to render output in the console in a way that (hopefully) won’t wrap, meaning it can be used in small console windows even if you have very long notes.

Non-default and encrypted profiles

Profiles are basically used to segregate notes by content, it’s up to use to decide how to actually use them. By default theca looks for profiles in the directory ~/.theca and will use the default profile (which can be either plaintext or encrypted) but you can add additional profiles with the command new-profile and specify which profile you want to use with other commands using the -p PROFILE option. If you don’t want the default profile to be default you can change it by setting the environment variable THECA_DEFAULT_PROFILE to the name of the profile.

Notes can easily be moved between profiles using the import and transfer commands, you currently cannot transfer a notes between two encrypted profiles or transfer notes from a plaintext profile to an encrypted profile, you can however import a note from a plaintext profile to an encrypted profile.

I’ve tended to (over the last few months) store general notes in the default profile and then have had separate profiles for projects e.g. theca-dev so notes that might need to stick around for a long time or are updated frequently don’t clutter up my general notes.

theca makes it relatively easily to create encrypted profiles and to encrypt/decrypt existing profiles. To create a encrypted profile you just need to use the -e flag which will prompt you to enter your key (which can also be specified using the -k KEY argument).

You can use the encrypt-profile and decrypt-profile commands to encrypt/decrypt plaintext/encrypted profiles you have already created respectively.

-e and/or -k can be used with the rest of the commands (add, edit, del, etc) to interact with encrypted profiles (otherwise an error will be thrown).

Syncing profiles

theca can take advantage of any existing syncing software you have setup (Dropbox, ownCloud, rsync…, etc) to share profiles between computers since the profiles are just flat JSON files. The default profile folder from which theca reads profiles can be set set via the environment variable THECA_PROFILE_FOLDER so to sync profiles you just need to set this variable to the path of some folder being synced and store your profiles there. For instance I use Dropbox to sync my profiles, and have my THECA_PROFILE_FOLDER set like so

$ export THECA_PROFILE_FOLDER=/home/roland/Dropbox/.theca

Integration

Since profiles are basically just flat JSON text files (well when not encrypted, but a simple Python key-derivation and decryption routine can be found in the README if you want to work with encrypted profiles) it’s relatively easy to write short scripts in your scripting language of choice (Python, Ruby, Perl, hell even BASH) to add, search, move, sort, transfer, import notes etcetcetc without having to add the feature in Rust to theca directly.

You can also output single notes, lists, and searches directly as JSON if you’d like to somehow tie that into your script by using the -j or --json flags.

Here are some random ideas you might want to implement that have crossed my mind

  • Email note reminders based on syntax at end of note bodies (e.g. !remind [email protected] in 1 day/1 week/1 month or !remind [email protected] every week)
  • Email weekly profile summaries
  • Email reminders based on notes with Urgent or Started statuses that haven’t been updated in a while
  • Add notes from emails to a special account
  • Note archiver (transfer notes older than x to the profile archive)
  • Store reports from CRON jobs in notes

Contributing

Contribute to theca on

Please do! A lot of the code is still quite messy and while it works there are a number of places that could use a bit of TLC. Pull requests for clean-ups, new features, or pretty much anything are more than welcome. For now development happens in the master branch but as soon as the stable Rust release comes out and I get around to releasing theca 1.0.0-stable development will move to the dev branch. Nightlies will always be built from the dev branch meaning they will be unstable-ish but will also contain the most recent features/bug fixes.