\ 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. \n The best way to do so?* > > ***Code something.*** \ --- \ Enter **[Hellfred](https://github.com/braddevelop/hellfred),** a collection of 3 mini-apps built on top of __[Hammerspoon](https://github.com/Hammerspoon/hammerspoon)__ so you can automate tasks, boost productivity and eliminate time-suck by programming shortcuts into your daily workflows. \ :::tip *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](https://github.com/braddevelop/hellfred)__* and `checkout` the `basics` branch. \ ```bash 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](https://github.com/Hammerspoon/hammerspoon/releases) 2. Install Hellfred: Clone the repository to your \``~/.hammerspoon` \` directory: \ ```bash 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](http://www.hammerspoon.org/go/#fancyreload)__) \ # 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: ##  \n 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. \n <https://gist.github.com/braddevelop/49c7e7c7c62350d93e7798ff2bf40541> \ **Configure** `Subscriber` **objects** :::tip `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. ::: \n 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. \n \ 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: \n `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. \n <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**. \ :::tip 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. \n 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](http://www.lua.org/manual/5.3/manual.html#pdf-_G)__ 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 of`c` 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. \n 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` \n 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** \n Enter Hellprompt (`shift` + `^` + `h`) and test out those commands. ***Inferno!*** Try: ```javascript browse news ``` and: ```javascript 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. \n <https://gist.github.com/braddevelop/b18f575ec347503628e7457217b6e187> \ **Configure** `Subscriber` **objects** Subscribers for Hellfuzz take a different structure to the other apps. \n Consider this structure: <https://gist.github.com/braddevelop/56e9c22c6f921575637c73d60920d208> **Note**: If `nextChoicesFn` is defined then `callback` is ignored. \ :::tip *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. \n 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. ```javascript git checkout extend ``` \ --- \ **Now go raise hell** `\m/` \