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 (
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.
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
- 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
Profiles are essentially used to segregate notes based on whatever reasoning you choose e.g.
diary, etc etc and can be either plaintext or encrypted.
There are two (well three) ways to get
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
i686-apple-darwinthat you can download and install using the packaged
install.shscript or by using the hosted
get_theca.shscript. 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 -s https://static.bracewel.net/theca/get_theca.sh | sh
get_theca.shwill 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
--nightlyflag which will allow you to revert
get_theca.shto 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
package-installer.shwhich is named
install.shin 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.shscript to uninstall
thecaif you wish that it no longer sullied your system
$ curl -s https://static.bracewel.net/theca/get_theca.sh | sh -s -- --uninstall
Build the binary from source
If you want to build from source you’ll probably want to get the latest nightlies of
cargo, these can be easily acquired by running (or again mangually install the binaries or build from source) or using
$ 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.
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
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 (
--none, the default option for new notes)
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
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
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 (
--reverse), sorted by the last time it was edited (
--datesort), limited to a certain number of notes (
-l 5 or
--limit 5), or outputed as 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.
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
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
decrypt-profile commands to encrypt/decrypt plaintext/encrypted profiles you have already created respectively.
-k can be used with the rest of the commands (
del, etc) to interact with encrypted profiles (otherwise an error will be thrown).
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
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
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
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 monthor
!remind [email protected] every week)
- Email weekly profile summaries
- Email reminders based on notes with
Startedstatuses that haven’t been updated in a while
- Add notes from emails to a special account
- Note archiver (transfer notes older than
xto the profile
- Store reports from CRON jobs in notes
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.