Protesilaos Stavrou: Commend on Unix versus Emacs

In this post, Protesilaos answers an email by one of his readers. In the email, the sender seems to assume that Emacs is bloated by definition, and that e.g. Vim isn’t, because it comes with less stuff baked-in and works well with piping – the core way to compose in *nix command lines.

The sender asks:

This video [of Luke] really provide some good reasons why to invest on ‘coreutils’ to build a small, maintainable and decentralized system rather than investing on a giant mutable system.

Emacs being the giant, mutable system, and the pipe-able Unix command-line tools comprising the “maintainable and decentralized system”. (That way of asking is loaded with assumptions already.)

Prot does a very good job at not preaching, and actually bringing forth useful arguments.

  • Vim has a lot of stuff built-in, like a terminal emulator, and isn’t that different from Emacs in that way. (Plain vi is a different beast.)
  • Prot treats Emacs “as a layer of interactivity on top of Unix”. That’s a very good description, I think.
  • There is non-negligible overhead in composing a system of many independent pieces. You end up writing a lot of glue code, so to speak. (And it can be rather brittle.)
  • Emacs ties things together into a coherent software where you can share stuff between pieces of functionality easily. You can copy from the Emacs shell and paste in a text buffer. You can perform mass text replacement from a UI you already know instead of having to learn syntax. (Opposed to sed/awk/…)

In closing, Prot points out that the underlying issue can be binary thinking (which is rather limited and avoids entertaining opposing opinions):

This hints at the kind of thinking that treats the world in simplistic, binary terms: Unix is simple VS Emacs is complex; Arch Linux is for hackers VS Ubuntua is for simpletons… Those are stereotypes that rest on misunderstandings about the intent and the purpose of each of those paradigms, their context-specific pros and cons, as well as the potentially numerous reasons one may have to opt for a given choice.

Worth a read during this time “between the years.”

Indie Support Weeks: Working Copy - Fully Featured iOS git Client

Teaser image

Since COVID-19 doesn’t seem to go away any time soon, I figured I might as well continue with #IndieSupportWeeks to show you what I use and can recommend.

A dev tool I use on iOS is Working Copy. Usually, I don’t interact with my project code at all from iOS, but when I do, I check git stuff with this app.

Over the past 10 years or so I’ve tried a couple git clients for light work on mobile, but Working Copy sticked with me ever since I was participating in the TestFlight beta.

For a casual git fan-person, Working Copy’s settings might be a bit overwhelming, but for developers, I think this is a very fine app to browse, search, push and pull, and even commit changes.

Now the “commiting changes from mobile” part in someone’s daily workflow is utterly confusing to me, because I cannot imagine what that’d be like on an iPad, say.

I have edited posts on my website this way to fix typos. That went well. I also used it for light maintenance of Open Source projects. But I haven’t tried to commit to my Swift projects, because I don’t see how editing Swift files without a compiler would be a good idea. Then again it’s not my job to figure out user personas for a mobile git client – I’m here to tell you that if you’re in the market for such a tool, Working Copy is good at that.

The one thing I can testament to is that it works without a hassle, and it works well. That’s not much, but that may also be all you truly care about.

Working Copy is a free download + a $19.99 one-time in-app-purchase to unlock all the features. It also has a 4.9-star rating on the App Store, so, wow!

How to Profile Slow Scrolling (And Other Performance Bottlenecks) in Emacs

I played around with Nicolas Rougier’s NANO Emacs configuration because it looks so hot and I wanted to try some of his tasteful settings myself. One thing that let me down for a couple days since I started eyeballing the package was performance. In my huge org files to organize app development tasks, scrolling was so-so. Pixel scrolling, which I discovered through Nicolas’s configuration ((pixel-scroll-mode +1)), didn’t work at all on my machine. I have a MacBook Pro 13” from 2020. This is a text editor. Something’s not right with my config.

Continue reading …

Uberabout Makes Your App’s About Window More Sexy

Teaser image

Martin Lexow created a sexier alternative to the default AppKit “About” window called Uberabout

You know, these things:

Default About window that comes with any AppKit/macOS app

The info available to be displayed there is:

  • app icon
  • app name
  • version number
  • build number

Now Martin came up with a drop-in replacement for the same info but with less ugliness:

Uberabout window that your app could have, too

Check out the GIF in the project’s readme to see its 3D transition effects in action!

Sadly it’s only for macOS 11.0+, so for projects pre-Big Sur, you have bad luck. But it’s written with SwiftUI, so you may still learn one thing or another, or adapt the code to your project if you want!

Apple’s App Store Small Business Program Enrollment Is Super Simple

I don’t know about you, but sometimes, and the end of an exhausting day, I find the prospect of filling out yet another form almost frightening. At the very least intimidating. Some days, I’m just not in the mood to be bothered. Even with tracking open loops meticulously, this opens up the potential to let things stay undone for far too long.

In case you’re prone to behave like that, I don’t want you to fall into this trap for your indie app business. So here’s good news. I checked out Apple’s App Store Small Business Program enrollment.

The App Store Small Business Program is literally just a handful of checkboxes to tick. That’s it. I completed it in 2 minutes, most of it spent in the login form, I guess.

If you earn less than 1mio USD in revenue per year and want to see your App Store fees halved from 30% to 15%, apply as soon as possible.

If you apply before Dec 18th (this Friday!), your enrollment is expected to be done in time for January 2021.

It takes a handful of deep breaths to get through that. And I totally get why some of us at the moment absolutely need some breathing room as 2020 draws to a close. If yet another form to fill out is not your cup of tea, give this checkbox-based form a chance. You’ll not regret it.

OpenMoji Support in emacs-emojify

Teaser image

If you have no dignity (like me), you might enjoy displaying emoji in Emacs. I actually really like that when composing/reading email, and when I want to add colorful stuff like stars in my to-do lists. There’s this package, emacs-emojify, you might want to check out. When you install the package, it will download EmojiOne images by default. You can set up your own, and I found the OpenMoji set to look very nice. Clear lines, crisp shapes, very recognizable expressions in big and small sizes. Love it.

Continue reading …

Decorate NSGlyphStorage to Replace Glyphs On-the-Fly

There are many ways to affect the glyphs that are used to show text on screen. Since macOS 10.11 El Capitan (released in 2015), possibly the simplest override points are in NSLayoutManagerDelegate. Another, arguably more ancient way to replace glyphs on-the-fly is to override and customize NSGlyphGenerator. This predates the existence of NSLayoutManagerDelegate, and it’s not even available on iOS, so that’s how arcane the approach outlines here will be.

Continue reading …

Upgrading to Sparkle 2.x Branch

TL;DR: The Sparkle 2.x release branch is working fine for production when you switch from the ui-separation-and-xpc branch and enable DSA signing of updates. While updating TableFlip for macOS Big Sur, I figured I might just as well update my dependency on Sparkle to whatever they came up with in the past 18 months or so.

Continue reading …

Zettelkasten Method Introduction

Teaser image

Sascha wrote an introduction to the Zettelkasten Method, and after months of editing and polishing, we finally published in online!

What’s a Zettelkasten, you ask?

Think personal wiki of knowledge. But instead of merely cartographing what is in the world, you create new stuff from the things you collect, building up layers upon layers of ideas by connecting what you already have, and then making a big hypertext from it.

At first you have atomic ideas, then you begin to link them and think and write about their connection.

In other words, it’s a way to add layers of abstractions to your thinking and writing.

I use something like it for 11+ years now and the amount of cross-connections is very cool. Also, by using my Zettelkasten properly, I “accidentally” prepare blog posts for this site: every note is self-contained and written in a semi-publishable manner, so I could just copy and paste notes together to make an article. That’s the sweetest part of it: how it accelerates my writing.

Check out the intro and see how simple the actual implementation is.

Hide Traffic Light Buttons in NSWindow Without Removing Resize Functionality

I noticed that in macOS’s dark mode, a window without a visible title bar won’t draw a light border. It will draw a dark/black border, unlike all the other windows, and thus be a lot less visible than it needs to be. So for a floating helper window, I had to make the title bar visible, and then hide all traffic light buttons in the window’s top-left corner:

Continue reading …

Shorten Emacs Yes-or-No Confirmation Dialogs

Some commands in Emacs and its various packages are destructive. They require a confirmation by the user. These usually use yes-or-no-p, which won’t complete the command until the user replies by writing “yes” and then hits enter, or “no”, or aborts the command with C-g. Some of the commands that require confirmation in this way are overly protective, I find. Like projectile-kill-buffers (C-p k) which closes all open buffers for a project at once. I use this heavily when e.g. editing my website: jump into the project, edit a file or two, commit, then leave. I don’t want to type “yes” and hit enter just for that. (Please note that killing a buffer this way will still ask me if I want to save or discard changes, so the kill command alone is not destructive.)

Continue reading …

Follow Link at Insertion Point in NSTextView

Teaser image

If you ever wondered how to programmatically trigger a click on a link in a NSTextView, here’s one way to do so. This assumes that clickable links are not stored as temporary attributes in the NSLayoutManager, but permanently as part of the “model” in your NSTextStorage. You can then ask the storage for the attribute at the cursor/insertion point location:

Continue reading …

Fix Your Damaged Mac App Store App by Parsing the App Store Receipt Dates Correctly

If your customers get this message when downloading your app from the Mac App Store: XYZ is damaged, remove it and download again from App Store. … it might be because you’re parsing the App Store receipt dates wrong! Apparently, Apple began to change Mac App Store receipt date formats recently: When you parse receipt dates, account for both variants. To make things easier for you, strongly consider to use ISO8601DateFormatter (NSISO8601DateFormatter in Objective-C) which should (!) handle multiple variants of ISO-8601 dates for you.

Continue reading …

Indie Support Weeks: Use DropDMG to Create Your App Downloads

Teaser image

I’m continuing the #IndieSupportWeeks today.

In the past months, I deployed a couple of app updates. Not as many as planned, but still. My app downloads are compressed DMG files, or disk images. With these, you don’t need a Zip. DMGs usually come with the app bundle and an alias to /Application so you can “install” an app quickly via drag & drop. This is probably the most successful and easiest way to ship downloads that work with macOS App Translocation. If users run an unzipped app bundle from their downloads folder, they’re screwed.

Screenshot of DropDMG

Over the years, I tried a couple of approaches, and I found that I had the most success with DropDMG. The visual preview is very accurate, and I never had any problem with the resulting DMG files. It beats fiddling with the command line every day.

DropDMG is an essential tool in my workflow to ship applications. It costs US$24 at the moment, and it’s worth the money if you do indie app development to make money.

Make RVM’s Ruby Available to Emacs Shell Commands

No matter if you use exec-path-from-shell or not, Emacs will not be able to know your RVM-managed Ruby information. This drove me crazy. Most Emacs shell commands are invoked in an “inferior” mode, aka a “dumb” shell. This includes M-!, M-x shell, and also the projectile compile commands. That’s when some of your user login scripts will not automatically load, like the entirety of rvm, the Ruby Version Manager.

Continue reading …

Demonstrate Swift’s Lazy Initialization of Static Attributes Even when Using a Property Wrapper

I wanted to make sure that I’m up-to-date in regards to Swift’s lazy initialization of static attributes. So here’s a demonstration of a Swift property wrapper that produces debug output to check what’s going on, aka caveman debugging (because of the log statement, y’know). The output is as follows, demonstrating that the static var is initialized lazily when you access it:

Continue reading …

Comparing 2D Collision Detection and Hit-Testing Approaches in Godot 3

Teaser image

I played around with Godot and found that when my player character moved too fast, it would not collect items in its path. Here’s a short visual comparison of two approaches to move things in an engine like Godot. If you don’t know Godot: it is an engine, tool, and IDE to create cross-platform 2D and 3D games and GUIs. It’s basically Unity, but open source.

Continue reading …

How to Decode Human-Readable JSON Strings to Integer-Based Swift.OptionSet

I want to decode JSON that’s human readable but still represents a Swift.OptionSet. Traditionally, OptionSets are implemented with an integer-based rawValue, because that gives you the set algebra for free. Here’s my type: Here, all represents the whole text of a document, for example, and selected stands for the current selected text, if any.

Continue reading …

Blog Series: TableFlip’s NSDocument File Type Issues and Fixes

This is an overview of a short series of posts I wrote about TableFlip’s 2020 bug. People were getting a “You don’t have permissions” error, a Sandboxing error, when they worked with .txt files, but not with .md files, even though the app treated them the same. The issue boiled down to a misconfiguration on my side that went by unnoticed until I enabled Sandboxing. I was wrongly defining document types in the app’s Info.plist, and I was reporting supported file types in the NSDocument subclass in a manner that didn’t work out well.

Continue reading …

Programmatically Select a NSSavePanel File Format to Fix Empty Selections

In my quest to vanquish bugs from TableFlip, we intially observed that file extensions would attempt to change after an external file change. It turnes out that this was my fault because I effectively always passed "net.daringfireball.markdown", even when the document type originally was "public.plain-text". Passing the wrong file type to NSDocument.revert(toContentsOf:ofType:) was causing the issue. Trying to use the optional NSDocument.fileType property first, and then providing a fallback, solved the file extension problem.

Continue reading …

Sorting Out Overlapping File Types

In my initial post about this problem, I talked about the observations and how I began to figure out where the permission problem came from. I turned out to be an attempt at changing the file extension from .txt to .md. When the user opens a .txt file in your app, macOS makes sure you only get access to that exact file path by default. You cannot just write willy-nilly anywhere else without the user’s permission. File extension changes are included in this protection.

Continue reading …

Sandboxing and Declaring Related File Types

When I researched what caused TableFlip to lose permissions to write out files, I learned about “related items” in the Sandbox. A good example from the docs is to open a movie file plus its subtitle captions together. The user would select the movie in an NSOpenPanel. This usually grants access to the movie file directly per Sandboxing restrictions. You can declare the subtitles file to be a related item so that the Sandbox allows you to read both. That’s clever.

Continue reading …

Observations of the Curious Problem of NSDocument-Based App Changing the File Extension

Teaser image

Users have reported problems with TableFlip saving their files recently. One wrote about it in the Zettelkasten forums, if you want to see the problem in context. To reproduce the problem: when you open foo.txt in TableFlip and a text editor, then change the file in the editor rapidly, TableFlip would show a “You don’t have permissions” error once you tried to save changes from TableFlip later.

Continue reading …

Natural Language Toolkit Word Counter

Back in January when I drafted this post, I had just discovered Apple’s NaturalLanguage.framework. I still don’t know how powerful it really is, but it’s useful for a very simple task already: Counting words. In English and German, I can get pretty accurate results with a String.split at punctuation marks and whitespace. In French, you will get skewed results because these nices folks decided to put whitespace between quotation marks and quoted text.

Continue reading …

Delete the Next Word or the Current Selection in Emacs with the Same Shortcut

When you delete a character or the current selection, you usually hit C-d (Control + d) in Emacs. I got into the habit of revising drafts by deleting whole words, and the M-d (Meta + d) key combination is super useful for that. It also works into the other direction with backspace. It’s essentially the same effect of +backspace everywhere else in macOS.

Continue reading …

Indie Support Weeks: beorg

Teaser image

This is week two of the COVID-19 lockdown that led to #IndieSupportWeeks to help independent developers get a shoutout and maybe find a couple extra customers.

For today’s installment, I picked beorg.

beorg is a bit weird. It’s basically a task manager and calendar, but based upon plain text files that I sync via Dropbox. It’s not a particularly user-friendly application, and its UI didn’t win any prizes, unlike e.g. Things or OmniFocus (I’m often confused by the app icons and lack of labels, but also glad because my iPhone 5S screen is so smol). So why did I pick this app, then?

Urist likes beorg for its visual representation of plain text outlines

beorg is a mobile companion for my Emacs org mode files. It’s capable of handling org mode outlines, and parts of these outlines can be tasks or TODOs, and you can group them in projects, and then display an overview or “Agenda” – and things get out of hand quickly from there. Emacs is ridiculously customizable, and org mode is no different. beorg makes these information available on mobile.

So since over the years I moved from OmniFocus 1 to Things to OmniFocus 2 to Emacs, I got used to viewing tasks on my mobile phone and iPad; and I really much like the capability to capture information on the go. A piece of paper will do most of the time; but having a web clipping synced to my computer directly is nice.

You can even write Scheme scripts inside beorg! I haven’t touched that topic at all. The REPL (yes, it has a REPL!) provides a sandbox for experimentation, and by convention beorg will load and run init.org file from your list of files right after bootstrapping. You can even customize the app’s UI with this. Writing org files that auto-execute during launch to customize the behavior of the editor is a long-running theme, see this random example (source).

Regarding the business model: most stuff is free, and the free version will get you really, really far. You currently can buy access to additional features:

  • “Properties” will let you add custom key/value pairs to any item; it’s mostly a UI affordance for the plain text underpinnings
  • “Encryption” to, well, encrypt your items or files
  • “Task Timers” to track how long you work on a task (ahem, I suggest an automated service like Timing for that; note: this is an affiliate link)
  • “Templates” are pretty self-explanatory, and org mode capture templates can get out of hand and cover JIRA ticketing, for example (did I mention you can configure org mode to sync with JIRA?)
  • “Export Themes” are CSS styles to generate HTML from your outlines because, well, org mode is supposed to be a structured markup language for HTML and LaTeX export and such thing
  • UI Themes” for Solarized and additional dark modes in the app
  • “Saved Searches” to more quickly access the results of complex searches
  • “Box Sync” to … sync to Box.net (beats me why this of all things is an add-on)

The developer provides release notes for updates in the app, which I absolutely adore for this kind of “make it your own” pro user application, to make sure I keep up-to-date with the good stuff. The tip jar that goes along with it is probably the main source of his income – at least as much as I’m concerned. The updates are really good and much appreciated.

Indie Support Weeks: Soulver

Teaser image

In this awkward time of COVIC-19 lockdowns, folks will begin to struggle to make ends meet. I know from some folks that their salary was reduced to 60%, which is better than 0%, but still troubling. Indie developers of most non-video conferencing software suffer from similar declines in income. That where #IndieSupportWeeks come into play: share some of your favorite indie apps to spread the word and help the developers stay afloat.

This time, I want to point you towards Soulver by Zac Cohen. Zac is a very friendly and helpful person, and Soulver is a great app, so I hadn’t had to think twice.

A couple of calculations in the text editor to the left, with the result column to the right

I use the iPad app whenever I try to make sense of a change in expenses, e.g. when I move, when I compare contracts for my phone or insurance, or want to roughly plan a vacation. It’s really great for back-of-the-envelope calculations.

Soulver is a line-based text editor that performs calculations for you, with some understanding of semantics as well: For example, the phrase 30% of $800 will evaluate to $240. And with support for variables, you can begin to make more complex calculations that are perfectly readable in the long term.

Here’s a crude UI mockup, where the right column is the computed result, and monthly rent is a variable:

monthly rent = $1,900 // 2018      | $1,900
monthly rent = $2,150 // 2019      | $2,150
                                   |
monthly rent / 4 people            | $537.50

It’s available on iOS and macOS.

Other resources:

Now Hiring: Freelance Mac Dev

I’m looking to hire on help for my Mac app projects. You can apply now and I’ll be looking forward to pick someone in March. Ordered by importance: Have another look at my apps to see what kind of stuff I work on. This list of stuff is mostly about self-contained modules. You can think of these to be greenfield projects, so you don’t need to deal with existing code most of the time. We will design components from UI to API together and you’ll get to be as creative as you want and the project allows.

Continue reading …

Auto-Growing NSTextField

I ran into a situation with a window that is movable by its background and a text field inside it. The text field draws neither border nor background, so to the user, it looks like an input field directly on the window’s background. Much like the Spotlight search box. Even when a window’s isMovableByWindowBackground is enabled, a NSTextField captures click and drag events, and it changes the pointer to a text insertion variant (NSCursor.iBeam). All that is weird when you don’t know there’s a text field at that point. And you cannot know how large the text field is if nothing is drawn there. When the background is gone, this feels pretty weird.

Continue reading …

NSProgress with KVO-based Finish Callbacks

Here’s NSProgress subclass that allows block-based callbacks for finishing the progress in a new callback called finishHandler that should work the same as the existing handlers. By default NSProgress (or with Swift just Progress) comes with handlers for resumeing, pausing, and cancellation events, but not for finishing. I don’t know why.

Continue reading …

WhatsNewKit v1.2.0 Supports Multiple Update Notices at Once

Teaser image

I was getting back to fix a couple of small issues in The Archive and release an update when I noticed that one new feature I added, a statistics status bar, made most sense when hidden by default to avoid UI clutter. But how do people notice the new feature, then? Well, that’s what the “What’s New” window is for. To make it support a history of amazing changes, I adapted my very own WhatsNewKit to support this. And there you go, WhatsNewKit version 1.2.0 is out now and supports multiple update notices!

Continue reading …

Thread Safe Property and Resource Access with the Transaction Wrapper

Here is a transaction type to copy & paste into projects to encapsulates thread-safe read/write access: Just make sure to not use the main queue, because .sync call from main to main will deadlock your app! It ensures you read values synchronously, which isn’t dangerous, and enqueue and execute write operations in order. This is useful if you need to access any resource from multiple threads and want to avoid the overhead of mutex locks.

Continue reading …

Lock App Features Behind a Paywall and Enforce the Lock in Code

Teaser image

I stumbled upon an interesting coding problem in a recent macOS project related to in-app purchases. IAP can be represented by a feature option set in code. How do you secure UserDefaults access in such a way that accessing values can be locked via the IAP available feature options? (This also applies to tiered licenses, like a “Basic” and a “Pro” feature set.)

Continue reading …

Show Light Text on Dark Recessed NSButton with an Image

This is how I made dark NSButton with the NSButton.BezelStyle.recessed display legible light text on dark background with macOS Mojave an up. Recently, a user of The Archive pointed out that the in-app guide doesn’t display properly with a light system appearance. In dark mode, you wouldn’t notice the problem, but in light mode, the button colors rendered them illegible. Only when you press a button does its text light up properly for its background color. Have a look:

Continue reading …

Whole Value Pattern

I often forget the name of this thing, then I search for it, and forget it again later. It’s the Whole Value Pattern. The “Whole Value” pattern means you should get rid of using primitive or literal data types as quickly as possible. (Since Swift has no non-object primitives, you have to look a bit harder to spot these, but “literal value” is a pretty good indicator.)

Continue reading …

AppMover Swift Library to Move Your macOS App to the Applications Folder

Oskar Groth published a modern iteration of the “LetsMove” framework where you can show a dialog at app launch, asking the user if she wants to move the app to /Applications first.

This is still a crucial feature if you distribute downloads that unpack into the ~/Downloads folder: Gatekeeper’s App Translocation will actually start it from a random sandboxed folder. To prevent this from happening, distribute your apps as a DMG with a shortcut to /Applications to nudge your users to move the app there directly.

Get https://github.com/OskarGroth/AppMover on GitHub.

See also:

Community Trumps All

This is not a pun on the U.S. president. Going through stuff from the past year, I just noticed how much more amazing daily life feels with a community. In the past 2 years, I helped found two communities: Without the local group of Urban Sketchers, I wouldn’t have progressed with my watercolor skills; and without the forums, there wouldn’t be a lot of places to hang out to talk about what I find most interesting about personal knowledge management: creating new insights!

Continue reading …