Thanks to BetterTouchTool for sponsoring BrettTerpstra.com this week! I’m a long-(long-)-time fan of this app, and I’m really excited to see it switching over to a paid model. Help sustain great software!
BetterTouchTool is a little app that makes it possible to customize your input devices to really match your workflow. BTT allows you to configure various Magic Mouse and Trackpad gestures, to set keyboard shortcuts, bind normal mouse buttons, customize your Touch Bar, use the Siri Remote on your Mac and do tons more.
BetterTouchTool offers many actions to automate various tasks on your Mac, and allows you to assign them to any trigger you choose. Additionally it contains some handy features like window snapping, a basic clipboard manager, a screenshot editor and many more.
I spent some time over the weekend adding a few things to Cheaters that I’d been meaning to for a while.
First is the addition of metadata in cheatsheets. It’s not required on any sheet, but it opens up some possibilities for easier customization per sheet. The data is added in a JSON format, with %%%END as separator between the meta block and the rest of the sheet. In a Markdown file, this can go right at the top, e.g.
### Beginning of the cheat sheet
In HTML files this gets wrapped in an HTML comment:
Right now only a few keys are used, but it will be easy to add more (including attribution keys and external links). Unused keys are just ignored.
The current keys are id (just applies the specified id to the body element), style (allows an additional CSS stylesheet to be included), and layout. Layout can be any value but the only one that actually changes anything at the moment is multicolumn. If "layout": "multicolumn" is set in the metadata, the whole thing gets split into a horizontal layout. For sheets with sections broken up by h3/h4 elements and without a lot of tables, this actually makes a more easily-scanned page (I think). Find more details in the documentation.
Because I kept finding myself adding HTML ids and custom styles for certain cheatsheets that had different layouts, I decided that the style metadata key would allow the inclusion of external CSS files. These are loaded when a cheatsheet is opened, and removed when changing cheatsheets. Thus you can just restyle default elements without needing to namespace them, but you can always use the id meta to allow more specific targeting of elements.
I’d started out naming stylesheets by their associated cheatsheet (e.g. Markdown.css), but realized they should be more generic (e.g. h4dark.css) so they could be used more universally. It’s not a perfect system, and it still needs some cleaning up, but it’s definitely allowing more flexibility.
Table of Contents
If you’ve made use of Cheater’s “Fast Switcher,” you’ll probably appreciate this next bit. It’s pretty much the reason I started hacking on Cheaters this weekend.
When a cheat sheet is longer than fits in view (which is most of them), navigating can be a bit tedious. There’s the header navigation with , and . (comma and period), but I wanted a way to jump to a specific section. Thus, a table of contents was needed.
Typing “t” will pop it up. It’s generated from headers 1-4, plus tables with captions or th (whichever has an id attribute). For most sheets, this generates a workable navigation structure. A type-ahead filter field is automatically focused when it opens. Typing performs a fuzzy search on the available titles, and if it narrows down to just one, hitting enter will immediately jump to that section, closing the TOC in the process.
In Fluid’s menu bar mode, the Tab and Escape keys behave differently from most browsers, so tabbing from the filter input to the menu items doesn’t work. If you hit enter the first one is selected, in which case you can hit enter again (but not tab to the next). For now, this circumstance requires a mouse click if there is more than one result.
Escape will close the TOC popup at any time, but in Fluid pinned mode that will also dismiss the whole window, so the current solution is to click anywhere off of the TOC to dismiss it. A keyboard solution would be nice, but not in the cards quite yet.
A Quick and Dirty Server
Cheaters requires a web server to run locally. If editing your Apache setup or running MAMP isn’t your cup of tea, I’ve also included a tiny little script called cheat.sh in the cheaters folder. That will launch Python’s SimpleHTTPServer in that directory with an address of http://localhost:4000, which you can then plug into Fluid or Automator (or a web browser).
If you want to set this up to run automatically with launchd, it would probably be wise to add a cd /path/to/your/cheaters/folder/ line in before the python command and set it up with a KeepAlive key.
As part of the changes to the styling setup, I cleaned up all of the existing cheatsheets in the repository. This includes some changes to ones contributed by other people. Be aware of this if you’re updating a Cheaters install with any of your own customizations.
No matter what your current disposition, though, in this age of algorithmic overreach there’s something deeply satisfying about finding stories beyond what your loudest Twitter follows shared, or that Facebook’s News Feed optimized into your life. And lots of tools that can get you there.
Cloudflare’s mission is to help build a better Internet. We’re excited today to take another step toward that mission with the launch of 220.127.116.11 — the Internet’s fastest, privacy-first consumer DNS service.
Just in case you’re not already using Bartender, Vanilla is a free Mac app that lets you hide icons from your menu bar. Simpler in functionality, but also faster at disappearing those extra menu bar items than the current incarnation of Bartender.
Thanks to TextExpander for sponsoring BrettTerpstra.com this week!
TextExpander multiplies your team’s productivity by making up-to-date, shared knowledge instantly available to everyone who needs it.
TextExpander is available to your whole team on multiple platforms: macOS, iOS, Windows, and web. Using TextExpander, all of your team’s common responses are written and edited by your best writers for clear and consistent communication, accessible — and searchable — through simple abbreviations and keyboard shortcuts. And any time a change is needed, everyone’s snippets are updated immediately.
If you’re on a support or sales team, or if you’re in legal, medical, or real estate, TextExpander will change your life, leaving you more time to focus on what you do best.
You may have noticed that most of the original extensions for nvALT have kind of disappeared. For Chrome users, this one from Mustafa Paksoy is pretty great. Internal HTML-to-Markdown conversion and instant add to nvALT. Source available.
I’ve been on the Tower 3 private beta, and I can tell you it’s an exciting update for any Git user on Mac. Support for Pull Requests, a sweet interactive rebase GUI, a command palette for keyboard access to ANYTHING, and more. You can hold out for my review after it goes live, or join the beta now, your call.
The Cambridge Analytica revelations illustrate why we cannot trust Facebook to police its own platform. So now is as good a time as ever to remind you that — beyond deleting your Facebook account for good — there are some precautions you can take to protect your privacy and make use of Facebook as a utility without compromising your personal data.
I don’t know if you read the EasyDNS newsletter, but I’ve come to appreciate it as a very non-partisan source of information on privacy, technology, and the politics surrounding it. Post Cambridge Analytica revelations, my long-running question of how to handle the paradox of wanting to remain connected while wanting to remain safe, questioning my abillity to use tech to bring change while avoiding tech controlling me, have all become increasingly urgent.
Hey buddy, how you doing? I’m good, thanks for asking. You don’t seem good. What’s going on? Well, ok, let me just ramble through this for a bit. Cheaper than therapy…
Emma — my favorite pit bull and canine companion for 11 years — passed away suddenly last Thursday. It was devastating. It is devastating. A lot of you have been through the same (or worse) loss, many of you likely in recent memory. I had recently gone through it with our German Shepherd, Chance. Aditi and I had 2 weeks with him before he had to leave, so he got some “bucket list” time. Not for Emma, though. She woke up under the weather, didn’t eat, fell over peeing, got rushed to the vet, and never went back home1. But the fact that everybody loses loved ones always makes me feel bad about feeling bad about losing loved ones. Buck up, right?
In the meantime, “home” had come to mean different things for Emma. Aditi and I separated in late 2016 and officially divorced in 2017. I didn’t talk about it much, given I think we were both grieving for our marriage. Turned out that grieving process took forever. I think it might be harder when what you’re grieving for is still there but you’ve separated yourself from it.
But I always underestimate grieving times. Every time. I think it goes back to my early addictions, before I realized that numbing the shock and pain just makes it show up a decade or two later. When I was 12, both of my grandfathers died on the exact same day and my dog a week or two later. I found myself crying for all of them at 23, and then suddenly for the friends I’d lost over the years between. And at that point, with no apparent context, your grief makes less sense to those around you.
Not that making sense matters. The kindest thing anyone has ever said to me about grieving came from my friend Elle2, just last week: “There’s no wrong way to do this.” I don’t have to be appropriate, display certain behaviors, react in certain ways. The day my grandfathers died, I got sent to the principal’s office because I referred to their passings in a way that wasn’t “respectful” enough for my math teacher. I never realized it was ok to just feel whatever you felt, express whatever you needed to.
I told a few people who are waiting on things from me right now that “I need Friday off. I’ll recover over the weekend. Should be back at it on Monday.” Turns out you can’t just schedule shit like that (without drugs, anyway) any more than you can control how you’re going to feel at any given moment about any given circumstance.
It probably doesn’t help that I decided to give up nicotine starting just 2 weeks before Emma died. I quit smoking years ago, but I switched to vaping (e-cigs). And the problem with vaping is that it’s a much more available fix than having to light an object on fire. Even if you avoid vaping in public places, it’s still more accessible than a cigarette. So kicking nicotine has been a bear. Of course, I really don’t know what it’s supposed to be like; in 27 years I’ve never done it to completion. Never made it past the gum, the lozenges, the patches. I used patches for a bit this time, but today I’m 3 days into zero nicotine for the first time since I was a teenager. Emma would be proud.
Aditi and I have remained friends. There wasn’t a lot of drama in the whole thing, we just agreed weren’t as happy as we thought we could be3. I took Emma and Yeti (the beautiful monster feline) with me, but Emma regularly spent time with Aditi and Sirius (her GSD brother). In fact, one comfort has been that over the last few months Emma had a chance to see a LOT of friends who mattered to her. There’s an impressive lack of “unfinished business.”
Ok, so let me try to wrap this up. I do not know how long it will take me to grieve for the pet that was part of my daily life for 11 years. It took me at least a year to feel ok when grieving for my 11-year marriage. I also have no idea how long nicotine withdrawal lasts, but that one I feel like I can schedule more reliably.
If you knew Emma in any capacity, there’s an ASPCA memorial fundraiser set up in her name. The money all goes to the ASPCA in her memory, and between the one on Facebook and the memorial page, enough has already been donated that Emma would probably be embarrassed. But Aditi has worked with the ASPCA for years, and we’re both huge supporters of the work they do, so I think it’s a fitting way to hold Emma’s memory.
If you’re wondering, the issue was her lungs were compressed by a massive amount of swelling and liquid. It was likely cancer as the root cause, but given that the damage was irreversible and she was fading fast, we didn’t waste a lot of time on “why” just then.↩
I’m a bit shy about saying it, mostly because of concerns about other people’s feelings, but Elle is beautiful, caring, and brilliant, and I’m lucky to be her boyfriend.↩
That very obviously oversimplifies the situation, which is an injustice, but I spent a long time trying to figure out how to best explain it and ultimately realized I didn’t have to. I care deeply about Aditi, we’re still friends, and that’s probably already more than you cared to know. ↩
I’ve been using a workflow for web images for a while. The final part of the workflow is specific to my Jekyll install, so I’ll be taking a look at whether I can make that of more general interest or not. I think the first two parts are pretty cool, though.
We’ll start at the beginning of the optimization stage. You’ve created (or received) the final image destined for the web. You know the specific sizes the destination site needs for optimal display. On this blog, I start with 1600px-wide image for full-width, 700px for inset, both being the @2x size for high-resolution displays. The step between hitting “Save” and uploading it to the web, then, is usually to resize, output 1x and 2x versions, and optimize the results.
I do this with Hazel and a special naming pattern. When I save an image, I can add a series of special characters at the end, separated from the name by a double percent symbol (%%). When Hazel detects an image on the desktop or other defined folder that matches that scheme, it runs a script that parses out the options, does the conversions and optimizations, and then outputs file(s) with the correct names to the original location.
For example, if I save a file to the Desktop titled header_image@2x%%oh.png, the h will cause a 1/2 size version (i.e. @1x) to be output, and the o will cause both versions to be optimized (shrunk, squished, crushed, whatever is appropriate).
Any combination of options can be used, and in any order after the %% in the filename. Here are all the options:
o – optimize image
Tool chosen automatically based on file extension
c – convert PNG to JPEG
Ignored if the file is already a JPEG.
Because photographic images with a wide color range and no need for transparent background are significantly smaller as JPEG, I mostly use this one to automate processing of files sent to me by others.
h – create a half size image
Assumes the original file is the high res (retina) version and creates a 1x version at exactly half the original dimensions. If the original filename (before the %%) includes @2x, it will just create the same file without the @2x in the name. If not, it will add _sm to the second filename.
rXXX[xXXX] – resize to width or max-[width]x[height]
r followed by a numeric width will resize the image to a maximum width of that size (e.g. %%r800 resizes the image to 800px wide, with the height automatically determined). %%r800x600 will resize the image to a maximum width of 800px, or a maximum height of 600px, whichever is the larger dimension.
The script requires jpegoptim, pngcrush, and convert from the ImageMagick package. These command line tools have the benefit of being exceptionally scriptable, but also usually give me better lossless compression than any of the commercial image compression tools. Win-win.
All of the aforementioned tools can be installed with Homebrew:
Save the script from this Gist to a local file, make it executable, and add a Hazel rule to whatever folder(s) you want to watch for file saves.
The criteria of the rule should ensure that the file is an image format, and that the name contains %%. Then it should just run a shell script action, pointing to the script you saved above.
From here, just save images with the special filename format and give it a few seconds to run all of the other stuff in the background. Obviously, the same script and techniques could be used to just automate the build process in certain types of blogs, but this method gives me the flexibility to use the naming scheme on images with any destination, and handle/automate the actual upload and as a separate step.
As an example, the Hazel screenshot above was created using macOS screen capture in crosshair mode on my Retina display, saving a PNG to the Desktop. I renamed the file to ImageOptimHazelRule@2x%%r1600hoc.png and got an optimized JPEG version of the screenshot in 800px width and a 1600px @2x version.
I do, as always, hope that this script is useful to at least 5 people because then I feel like it further justifies the time I spend on saving time. If you’ve read this far, you probably know what I mean. On the next episode, I’ll share my scripts and tips for automating the generation of Open Graph images for social media sharing.
Thanks to FirstSeed Calendar for sponsoring BrettTerpstra.com this week!
FirstSeed Calendar is a beautiful calendar app that can handle both events and reminders. It is available for iPhone and iPad, and the Mac version will be available in April.
The first thing you will notice when using the app is its ease of use. Unlike most calendar apps, FirstSeed Calendar offers smooth scrolling in most everything you do. That means you can get to the events you are looking for faster than ever.
The other great feature is that the app shows the month calendar in full screen, until you tap on a date to have a closer look. This approach lets you have the best of both worlds: a micro and macro view of your events.
An innovative new feature that you will not find anywhere else is the new “condensed” week view. We eliminated the need for vertical scrolling in week view by showing events outside of the user-specified time as a list, thereby letting you focus on the time that’s most important to you.
Other great features include: reminder support, natural language input, birthday and anniversary support, a great event editor, paper organizer-like list view, and more.
Thanks to PDFpen for sponsoring BrettTerpstra.com this week!
PDFpen is the ultimate tool for editing PDFs and going paperless.
Organizing your documents, while ditching all the paper. Split and combine PDF documents to send just the right things to your accountant or your lawyer. Fill in PDF forms, even if they’re not interactive to begin with. Add page numbers, redact account numbers, and perform OCR on scanned documents. Search with ease, and find and highlight all instances of a specific term.
Step up to PDFpenPro to create PDF portfolios — collections of multiple PDFs and related files — great for presenting year-end documents.