One of my favorite programs for macOS is Ubersicht, which renders custom widgets to the desktop. The widgets available for download can be out-of-this world; some developers have published widgets to track the International Space Station or check the weather on Mars.
1. The Structure of the JSX component
Every Ubersicht widget exports four things: command (string), refreshFrequency (number), className (object), and render (function). All operate as one would expect.
You could also write a script in a different language, like Ruby or Python, and pass the output (so long as it can be printed to stdout) to the render function.
The value refreshFrequency is, naturally, the rate at which the widgets refresh their outputs. It is measured in milliseconds. Date updates every four seconds, but Forecast updates every hour.
className is an object that holds CSS information for the position and presentation of the widget. (If the output is spread across multiple css selectors, you can ‘import css from ubersicht’ to create more CSS objects. The documentation has more information.) JSX expects these keys to be camelCased, and not kebab-cased like ordinary CSS.
Finally, the function render can be as elaborate as you wish, but its return value should be a <div>. (Ubersicht will present this <div> according to the CSS rules in className).
Date is the simplest widget. The date command, which is included in every shell, displays date and the time. With a +, we indicate that we want a user-defined format string. Date interprets letters preceded by a % sign. The many symbols are difficult to memorize, so I consulted a guide.
The Tray widget informs me if two background applications (Flux and KeepingYouAwake) are active. The Tray widget calls a shell script (tray.sh) instead of executing a command string (like Date). The sequence of commands in tray.sh, adhere to a pattern that I will repeat. I’ll execute a command that outputs more data than I need. I’ll parse this data and transform it into something more presentable.
tray.sh call pgrep, a built-in shell utility that searches the table of processes and finds a match based on a regular expression pattern. It’s much like using grep, which stands for “globally search for a regular expression and print matching lines” — grep is probably one of the tools I use most often on the command line.
The syntax of shell scripts can feel user-unfriendly or downright hostile. In a test for a conditional, you have to mind the number of square brackets ([ exp ] v. [[ exp ]]). Take care that the inner expression is a space away from the closing brackets!
4. Network and Battery/Volume
The Network widget is more straightforward than Tray. The output of a macOS command (one that took some Googling to find) called airport is ‘piped’ to grep, which extracts the line of data we want. A pipe (|) ‘feeds’ the output of one shell command into the input of a second shell command. Pipes were a big deal when invented in the ’80s. (Brian Kernighan was excited to explain pipes in this ATT video on Unix).
The Battery/Volume, similarly, requires a macOS system command, and this one is called ‘ioreg.’ I can match the lines I want from ioreg with grep, but to further transform the lines, I’ll use sed (stream-editor) to remove extraneous information. Sed can match a regular expression pattern and replace it with a different pattern, and I chose to replace with an empty string.
The third great command line utility is AWK, which is actually its own interpreted language, and it’s a bit, uh, awkward to learn. We’ll use it here to do some arithmetic to display the percentage of charge left in my computer’s battery.
5. Temperature and Forecast
I converted the Fahrenheit to Celsius with AWK.
Fun conversion patterns to keep in mind:
004 C approx. 40.0 F
016 C approx. 61.0 F
028 C approx. 82.0 F
40.1 C approx. 104 F
Shell scripts are fun, with the right attitude. With this practice, I think I’m ready to start automating more of my workflow.