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)
  • “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 …