Hellfred or: How I Learned To Automate macOS and Become Hellishly Productive

Written by bradblundell | Published 2022/08/12
Tech Story Tags: automation | programming | coding | technology | productivity | macos | tutorial | hackernoon-top-story

TLDRHellfred apps are built on top of Hammerspoon so you can automate tasks and boost productivity by programming shortcuts into your daily workflows.via the TL;DR App

I wanted speed. IĀ neededĀ speed.

All this clicking around, all this searching, all the repetitive thinking and mental overhead was cutting into actually getting the job done.

I needed the robots to do the work for me.

I’d recently moved over to macOS after many years on Windows where I’d tinkered around with AutoHotkey.

As a relative Mac noob I started hacking around with Alfred,Ā KarabinerĀ and quickly found solace in the form of Hammerspoon.

Ah,Ā Hammerspoon. Yes, I had consumed the code and modules — ā€œSpoonsā€ — from the super-smart people coding and extending Hammerspoon and that gained me some great mileage, yet I neededĀ more.

Then, there was Lua. I wanted to upskill in Lua.
The best way to do so?

Code something.


EnterĀ Hellfred,Ā a collection of 3 mini-apps built on top ofĀ HammerspoonĀ so you can automate tasks, boost productivity and eliminate time-suck by programming shortcuts into your daily workflows.

It’s a way to map repetitive, time-consuming tasks to key sequences, commands or searchable texts.

TL;DR

So you want quick-fire? Skip to the installation andĀ tutorial section belowĀ orĀ download the repoĀ andĀ checkoutĀ theĀ basicsĀ branch.

git checkout basics


The Apps

Hellfire

A quick-fire, mode-based, hotkey-to-action mapping utility.

  • Supports single key triggers as well as key chord sequences as triggers.
  • Exposes virtually every key on the keyboard including modifier keys to use as triggers.
  • Modes allow the same trigger to have different behaviours under different contexts.

English, please?

When I type a character or a sequence of characters, then execute a specific function, but only if I am in a particular mode.

Ok. An example maybe?

  • When I typeĀ c then run functionĀ launchGoogleChromeAppĀ (but only if I am in Default Mode)
  • When I typeĀ wĀ followed byĀ m then run functionĀ changeToWindowManagerModeĀ (again, whilst in Default Mode)
  • When I type c then run functionĀ centerWindowOnScreenĀ (whilst in WindowManager mode)

Hellfuzz

A fuzzy-search chooser utility with choice-to-action mapping.

  • Supports multi-level (nested) choice sets.

English, please?

When I search through a list of choices and select one, then execute a specific function.Ā If my choice has subchoices (think: parent => children), then show me those so I can search through them.

Ok. An example maybe?

Suppose you have this structure:

  • When I type ā€˜goog’, then highlight the choice ā€˜Open Google’. Selecting this option will execute the functionĀ openGoogleInBrowser.
  • Alternatively, if I type ā€˜app’, then highlight the choice ā€˜Launch Apps’. Selecting this option will replace the current choices withĀ Terminal,Ā Notes, andĀ CalendarĀ (the subset of choices forĀ Launch Apps)
  • When I fuzzy search throughĀ thoseĀ and select one, Hellfuzz will executeĀ launchOrOpenAppĀ with the selected app.

Hellprompt

A commandline-like utility with basic string matching support.

English, please?

When I type out a command and submit it, then inspect my command for any matching string patterns and execute functions related to that command.

Ok. An example maybe?

  • When I type the command ā€˜open notes’ and then hitĀ enter, then execute any function with aĀ filterĀ (e.g. command must start with the word ā€˜open’) and behaviour (e.g. open app associated with ā€˜notes’) suitable to open the Notes app.

  • When I type ā€˜browse github’ and then hitĀ enter, then execute any function with a filter (e.g. command starts with the word ā€˜browse’) and behaviour (open url associated with ā€˜github’) suitable to open the link.


Installation: Firestarter

  1. Download and install Hammerspoon
  2. Install Hellfred: Clone the repository to your `~/.hammerspoon ` directory:

git clone https://github.com/braddevelop/hellfred.git ~/.hammerspoon

Bootstrap: Light it up

There is aĀ bootstrapĀ fileĀ for Hellfred with a pre-configured setup. Let’s reference it in Hammerspoon’sĀ init.luaĀ file.

https://gist.github.com/braddevelop/bac92b6797c087ca42f9363aab4972e0

Save the file and reload the configuration (or save yourself some time and useĀ fancy reload)

What’s in the box? Try out the pre-configuration

Out-the-box the 3 Hellfred apps are ready to use and are pre-configured with a quick-start example. Let’s test it out to make sure everything is wiring and firing.

Try Hellfire

  • OpenĀ HellfireĀ with the hotkeyĀ shift + ⌘ + h
  • Type the characterĀ c
  • The repo for Hellfred will open in a browser.

Try Hellfuzz

  • OpenĀ HellfuzzĀ with the hotkeyĀ shift + ⌄ + h
  • Type in the word ā€˜wiki’
  • This highlights the option ā€˜Open Hellfred wiki’
  • HitĀ enterĀ and the wiki for Hellfred will open in a browser

Try Hellprompt

  • OpenĀ HellpromptĀ with the hotkeyĀ shift + ^ + h
  • Type ā€˜open code’
  • HitĀ enterĀ and the code repo for Hellfred will open in a browser

WhatĀ Hellfire,Ā HellfuzzĀ andĀ HellpromptĀ achieve is map aĀ triggerĀ orĀ inputĀ to anĀ actionĀ orĀ behaviour,Ā if-this-then-that, and whilst we have just demonstrated using each app to achieve the same outcome, you will find each app more suited to certain use cases than others.


Tutorial: A basic setup

What we will be programming

Now let’s turn up the heat and configure something a little more useful. We are going to program each app to solve the following scenarios so that you can get the hang of things:

  1. A simple app launcher
  2. A url launcher for commonly visited links

You can find the final files for this walkthrough in the hellfred/extend/basics directory on the repository’s basics branch.

Patterns to note

Each app follows a similar set of steps.

  1. Initialise the app with a hotkey binding
  2. Configure `Subscriber` objects (This could be done in hellfred-bootstrap.lua but we will be creating separate files to keep things squeaky clean. We’ll leverage factory methods to make object creation a breeze)
  3. Register the subscribers with the app
  4. Hotkey to run the app
  5. Destroy time-sucking tasks

Setup for Hellfire

Hellfire works a little something like this:


Application Launcher

Initialise the app

This is already done with the pre-configuration in hellfred-bootstrap.lua. Feel free to change the hotkey to something else.
https://gist.github.com/braddevelop/49c7e7c7c62350d93e7798ff2bf40541

ConfigureĀ SubscriberĀ objects

triggers and callbacks are user-defined and wrapped inside simple configuration objects. These objects, act as subscribers when registered with the respective app and notified whenever something important happens inside the app.


Subscriber objects for Hellfire follow this structure:

https://gist.github.com/braddevelop/20c9c5b97a85a9a5c4cb924b511e494a

Note: IfĀ fireIfModeIsĀ is not defined, Hellfire will set the ANYĀ mode by default, meaning the callback will fire in any mode when triggered.

Create the following directory structure if it does not exist:Ā hellfred/extend/basics.

Then create a new Lua file inside theĀ basicsĀ directory calledĀ hellfirepack-applications.lua— the file naming convention has no importance.

Add this code:

https://gist.github.com/braddevelop/c12d37d64ce75b83a195666317a10aa2

Register the subscribers with the app

Back inĀ hellfred-bootstrap.lua, we need to register the pack of subscribers we have just configured.

https://gist.github.com/braddevelop/2298469b805978062421f5a09d01d11a

Run the app

Enter Hellfire (shift + ⌘ + h) and type any of the new triggers:
fĀ to open Finder app,Ā tĀ to open Terminal orĀ nĀ to open Notes app.

Link Launcher (using Hellfire Modes)

ConfigureĀ SubscriberĀ objects

Alright now let’s configure the subscribers for our Common Links url launcher. Create a new Lua file inĀ hellfred/extend/basicsĀ calledĀ hellfirepack-common-links.lua

Add this code:

https://gist.github.com/braddevelop/7d637464f45d2d9a4641e365ad2f20a1

Register the subscribers with the app

Back inĀ hellfred-bootstrap.lua, we need to register the pack of subscribers we have just configured.
https://gist.github.com/braddevelop/f0dafb518797620747044afbc20da060

Run the app

Enter Hellfire (shift + ⌘ + h) and type any of the new triggers: t, g, h or s.

Hang on!Ā Did you notice that typing the triggerĀ tĀ launchedĀ TerminalĀ as well asĀ opened theĀ TechCrunchĀ website? That’s probably not what we want to happen. Let’s take advantage ofĀ Hellfire’s ModeĀ feature.

Modes offer a way to have the same trigger behave differently under different contexts.

By default, Hellfire initialises in a mode called…you guessed it… ā€˜Default’ mode.
We can configure some custom modes to use with Hellfire so that triggers can behave differently under different modes — or ā€˜namespaces’ if you like.

Consider this flow:

Create a new Lua file inĀ hellfred/extend/basics calledĀ hellfire-modes-extended.lua.

We will create a separate mode for the common links triggersĀ to fire in.

Add this code:

https://gist.github.com/braddevelop/1e3f345076a8cd5c4cdf843cad785c9e

We are going to require this file inĀ hellfred-bootstrap.luaĀ so it isĀ globallyĀ accessible. We will do the same with theĀ Hellfire Modes fileĀ so that we have access to Hellfire’s built-in modes in other parts of our application.

Add the following code inĀ hellfred-bootstrap.luaĀ (under the metadata section, towards the top of the file)

https://gist.github.com/braddevelop/04a4ec21aab06f50760d1082b216426f

Now we need a way to change the mode to our newĀ Common Links mode.

We’ll use the key sequence ofc followed byĀ l.

We also need to be able to get back toĀ Default mode

We’ll use the semi-colon;Ā as a trigger.

That’s next…

ConfigureĀ SubscriberĀ objects that trigger mode changes

Create a new Lua file inĀ hellfred/extend/basicsĀ calledĀ hellfire-mode-triggers.lua

Add this code:

https://gist.github.com/braddevelop/283acacb9634590208c3b29b6039dc12

Register the subscribers with the app

InĀ hellfred-bootstrap.lua, register the subscribers for the new mode triggers:

https://gist.github.com/braddevelop/8afc4a576d550415f22c3c6fbf4152f1

Test switching between modes

Now enter Hellfire (shift + ⌘ + h) and toggle between the two modes. Modes FTW!

Update subscribers to work in modes

Now we need to update our subscribers inĀ hellfirepack-common-links.luaĀ so that they only fire whenĀ Common Links modeĀ is active.

We will update the factory method and assign _G.HELLFIRE_MODES_EXTENDED.COMMON_LINKS toĀ fireIfModeIsĀ instead ofĀ nil.

The updated method should look like this:

https://gist.github.com/braddevelop/152a16f87efe55f08e7ed7139225f757

We also need to update our subscribers in hellfirepack-applications.lua so that they only fire whenĀ Hellfire’s Default modeĀ is active.

The updated method should look like this:

https://gist.github.com/braddevelop/8ed8dea04397b0471299c8c89f8a9ae0

Run the app

Enter Hellfire (shift + ⌘ + h) and toggle between the modes. The trigger t now behaves differently depending on the mode that Hellfire is in. Hell yeah!

Setup for Hellprompt

This is how Hellprompt functions:

Application and URL Launcher

Initialise the app

This is already done with the pre-configuration inĀ hellfred-bootstrap.lua. Feel free to change the hotkey to something else.

https://gist.github.com/braddevelop/11e9b4871182f90c57313ab6ffa939a4

ConfigureĀ SubscriberĀ objects

Subscribers for Hellprompt take a different structure to those for Hellfire.

Consider this structure:

https://gist.github.com/braddevelop/c247d1d1429234c96f3e8c7d8a0b48df

Note: IfĀ filterĀ is not defined then the callback will always be executed.

Create a new Lua file inĀ hellfred/extend/basicsĀ calledĀ hellpromptpack-commands.lua

Add this code:

https://gist.github.com/braddevelop/6b18219f83fcf69826083d5dfce5d06f

Register the subscribers with the app

Back inĀ hellfred-bootstrap.lua, we need to register the pack of subscribers we have just configured.

https://gist.github.com/braddevelop/f1b75646b7330fcb1c993a5737fd7d61

Run the app
Enter Hellprompt (shift + ^ + h) and test out those commands.Ā Inferno!

Try:

browse news

and:

open terminal

Setup for Hellfuzz

This is how Hellfuzz works:

Application Launcher

Initialise the app

This is already done with the pre-configuration inĀ hellfred-bootstrap.lua. Feel free to change the hotkey to something else.
https://gist.github.com/braddevelop/b18f575ec347503628e7457217b6e187

ConfigureĀ SubscriberĀ objects

Subscribers for Hellfuzz take a different structure to the other apps.

Consider this structure:

https://gist.github.com/braddevelop/56e9c22c6f921575637c73d60920d208

Note: IfĀ nextChoicesFnĀ is defined thenĀ callbackĀ is ignored.

To make things easier we’ll use a helper method to configure subscribers for Hellfuzz

Create a new Lua file inĀ hellfred/extend/basicsĀ calledĀ hellfuzzpack-apps-and-links.lua

Add this code:

https://gist.github.com/braddevelop/3564ad1ec286a30eca1abb94cfd6a69a

Register the subscribers with the app

In hellfred-bootstrap.lua, register the pack of subscribers.

https://gist.github.com/braddevelop/a90f9d5635377d74b145a892845c8273

Run the app

Enter Hellfuzz (shift + ⌄ + h) and type in a command. For example start typing the wordĀ ā€˜Terminal’, you’ll see the option to open Terminal is highlighted. PressĀ enterĀ and Terminal opens.Ā Smoking hot!

Link Launcher (using nested choice sets)

A handy feature of Hellfuzz is the ability to nest sets of choices.

Consider this updated flow:

Let’s try this out on our Link LauncherĀ task, we’ll create the following hierarchical choice structure:

Update the code inĀ hellfuzzpack-apps-and-links.luaĀ to the following:

https://gist.github.com/braddevelop/384b0ae9629faca95d5d4cb519cd8e61

Now enter Hellfuzz (shift + ⌄ + h) and start searching for ā€˜Common links’. You can select the ā€˜Common links’ choice, and the sub-set of choices fromĀ commonLinkNextChoicesĀ will be displayed and can be fuzzy searched. Selecting any of the link options will open the respective url.


Extensions: Add fuel to the fire.

Look out for upcoming Hellfred experiments and extensions on the repo by checking out theĀ extendĀ branch.

git checkout extend


Now go raise hellĀ \m/


Written by bradblundell | Thing breaker : Code wrangler : Automation junkie : Digital illustrator : Aspiring musician
Published by HackerNoon on 2022/08/12