Convert MS Word DOCX Files to Markdown with Images

I don't know when was the last time I received a Microsoft Word .docx file. However long the streak may have been: it has been broken today. The document contained links and embedded images. I was instantly taken aback by the prospect of all the manual labor of extracting the images and saving them to files, not even knowing how MS Word behaves nowadays.

Continue reading …

Lightweight CrashReporter Library for Mac Released

The wording here is 100% Brent’s achievement. Love the humble tone.

I compiled a crash reporter library with CocoaPods support. Check it out:
https://github.com/CleanCocoa/CrashReporter/

The past couple of days, I've been working on integration of an automatic crash reporter. Turns out that on some machines The Archive is crashing regularly during search, and I want to track this down. I need data by more than the most courageous users who can venture into the Console to track down crash report files and send them to me.

So I bit the bullet and began work on a server script that would accept crash report files and email them to me. I think that's better than making users email me crash reports directly. Not everyone has Mail.app set up on her Mac, after all.

Fortunately, Brent Simmons open-sourced NetNewsWire 5 and blogged about his crash reporter. Brent has decades of experience on the Mac, so whenever he publishes a practical tip, I listen.

Just have a look at the code: Collecting .crash files and sending them over? Sounded simple enough! NetNewsWire even sports a very humble crash reporter UI, and automatically sending reports on the user's behalf if the user choses to do so. The required Swift types are simple enough to integrate once you figure out where Brent put all the helper extensions :)

I cannot stress enough how amazing open source is. All this experience, assembled in publicly available code repositories for everyone to grab and use. This is crazy.

I am now rolling this out for my apps, starting with the WordCounter and The Archive on their respective "beta" update branches to see how it works in practice. The Swift code is simple and I trust it doing its job. But the server script, well, it needs to be battle-tested now!

I'm going to add public-key encryption of messages and/or some sort of authentication to prevent malicious attackers from spamming me with emails that, well … I send to myself.

Move! Work Break Timer v1.4.0 Released

I just released an update to Move!, the work break app I develop and use. It fixes a couple of user experience issues, like displaying a Dock icon when you view the preferences so you don't lose the window.

Also, the app's preferences didn't display license details properly on Mojave and above. The app now uses Swift 5 and updated external libraries under the hood, is properly notarized (hello, Catalina!) – and a couple of MiB larger than before. I am looking forward to when we can depend on the Swift runtime being available on user devices.

Fixed Code Highlighting on the Blog

I manually edited about 400 occurences of code block markers from #!swift into \“swift`. I hope I didn't break anything in the process. So far, things look good. If you find oddly looking posts or broken code blocks, please tell me about them. There's no way I can find problems on my own in 10 years worth of blog posts :)

Continue reading …

Fold Current Level-1 Heading in Emacs Org-Mode Outlines

There's no standard shortcut to fold the current subtree of an org-mode outline. When I work in org-mode outlines, I usually am 3 or more levels deep into a so-called "subtree" and want to get back to the root item, fold it to hide the details, then drill down into another item. I use that when I am working on an app and want to have a look at a planned milestone nested deep down at a different point in the outline.

Continue reading …

Combine E-Book for Free

There is a free ebook out there that teaches you the basics of Combine, Apple's reactive framework introduced at WWDC 2019. It is pretty long already, given the time author Joseph Heck (@heckj) had to learn about Combine and then write about it. From what I saw, I think it's a good introduction to reactive programming in general.

Seriously, you should read it: https://heckj.github.io/swiftui-notes/

And the book's source is available, too! https://github.com/heckj/swiftui-notes

From the repository's name, swiftui-notes, and this description:

A collection of notes, project pieces, playgrounds and ideas on learning and using SwiftUI and Combine.

… I can only assume it gets expanded even more over time to include both SwiftUI and Combine!

Check it out and share it; Joe Heck deserves some internet love for his efforts.

Post Overview Updated

I don't know what's going on this week, but I have written a lot for the blog. I also carved out an hour and a half today to update the structured overview of articles on this website. I always wanted to make it a good entry point but didn't update it during the transition to another blog platform, then back again, and now it's 2 years later already. Phew!

Slides for the "More Money, More Control" Webinar on Selling Outside the Mac App Store

Today I noticed that I never followed up on my FastSpring webinar of 2017 called "Beyond the Mac App Store - A Practical Guide to Go From Code to Cash" with the slides! Sorry, folks! I'll also upload the checklist we served attendees. You can find the slides on slideshare.net, because I have an account there and don't know what else to do with PDFs: https://www.slideshare.net/DivineDominion/beyond-the-mac-app-store-a-practical-guide-to-go-from-code-to-cash

Continue reading …

TableFlip Mac App Store Experiment Stats: Sources

Here's some more background info for indie devs. To follow up the release of TableFlip on the Mac App Store and me noticing that yes, people buy the app without any marketing, I wanted to share sales origin stats today: according to the available data collected by the App Store, 100% of purchases were made after a search inside the Mac App Store so far.

Continue reading …

WordCounter for macOS Version 1.5.0 Released

I updated my app the WordCounter for Mac to v1.5.0 today. This update includes a couple of modernizations behind the scenes, but most importantly fixes problems that were related to the app being a Dock-less menu bar app. You couldn't manage any of its windows well. Now you can, because when any additional window is shown, a Dock icon is added on the fly.

Continue reading …

How Do You Activate Sparkle's XPC Services?

The Sparkle XPC fork is even better than I would've imagined! As I mentioned in the previous post about Sparkle's XPC branch, you can switch to the new framework version and the new types without having to change much else. The new API is very similar to the old one. If you switch to the work-in-progress ui-separation-and-xpc branch, then you can continue to use CocoaPods or Carthage if all you want is the new API.

Continue reading …

How to Migrate to the New Sparkle Updater XPC Branch

This is the first post in a series: The standard solution to provide app updates outside the Mac App Store is to use the amazing Sparkle framework. The releases of Sparkle don't support sandboxed applications well, though, so the core maintainer Kornel Lesiński (@kornelski) is working on a more secure fork of Sparkle next to the existing one. He's maintaining the regular Sparkle, and the fork. The fork features various XPC services to deal with Gatekeeper security configurations and Sandbox entitlements in a proper way. (I have to phrase it in such a vague way because I have no clue about the details, yet. Explanations are very welcome in the comments!)

Continue reading …

Use Shared NSUserDefaults for XPC and Interface Builder Nibs

The default Interface Builder approach of using a "Shared User Defaults Controller" object breaks down if your app preferences are not stored in the standard place. Both my apps The Archive and the Word Counter for Mac are comprised of multiple executable applications. For The Archive, it's the main app and the Quick Entry popup window. They share some settings, like which theme and font size is used. To share these settings, I rely on NSUserDefault (or just UserDefaults in Swift now). I cannot use the UserDefaults.standard, though, because that is tied to the currently running app's bundle ID. In the case of the main app, it's the ID of the main app; but for the Quick Entry helper – or any helper app –, it's the helper's bundle ID. This way, the defaults dictionaries are not shared.

Continue reading …

Imposing Bans and App Store Sanctions

Brent Simmons wrote about imposing sanctions by making apps unavailable in certain countries (in his case: Saudi Arabia) in November 2018. I never thought about the mere possibility of doing so. It's an intriguing thought: even when politics don't result in whatever you want, you can always be picky about who you do custom with. It's a power we have, a power every producer and craftsperson has. Turn down a business for moral reasons.

Continue reading …

From bash to zsh on macOS

Teaser image

In anticipation of macOS 10.15 Catalina, I have changed my shell from bash to zsh. macOS 10.15 will use zsh as the new default, and I was pretty sure that things will break immediately unless I prepare – so I did prepare, and I found the transition very simple.

Continue reading …

Browser-Like Navigation in The Archive

This weekend, I released an update to the note-taking app I'm working on for a while called The Archive. This update is pretty big for people not getting updates from the opt-in "Cutting Edge" update channel, because all of a sudden the app allows you to navigate back in time. The navigation stack (what you'd call browser history available from the navigation buttons in your browser) behaves like this:

Continue reading …

How to Add Files to mpd using python-mpd2

The music player daemon, mpd, and its client counterpart mpc operate on a managed directory structure. All paths are relative to this root directory. You cannot make mpd play a file from just anywhere, it seems. This is important to know when you script MPDClient using python-mpd2, because when you try to add any absolute path, even those pointing into the managed directory, you'll be in trouble.

Continue reading …

Emacs for Remote SSH Python Development

Teaser image

I am using Emacs for over a year now to manage my tasks. I like how I can mix tasks with long form notes in a single outline. It's good. We had to play with vi and emacs for a while at University. I'm very happy I got used to the very basics of both editors because I ended up using vi a lot when SSH-ing into remote machines, and now Emacs for everything else.

Continue reading …

Being Afraid to Change a Working App

Today I work on The Archive. The focus is on an issue brought up by the community. Search results don't update the sort order when you modify a note unless you refresh manually. In fact, the issue is expected behavior. The Archive, being a note-taking app where you can filter notes on disk with a live search, is designed to not update the search results for an active search term. Att all. This should prevent the note from disappearing from the results if you remove the search term from its contents. If you search for "foo" and get 10 results, the note you currently edit should not disappear when you cut the search term, "foo", from it. The Archive protects the search results; a mere live-reload would change the list to 9 results, removing the currently edited one, and that'd be pretty confusing.

Continue reading …

TableFlip Is Now Available on the Mac App Store

Teaser image

TableFlip is now available on the Mac App Store!

I also released updates to the non-Mac App Store version that fix CSV editing problems and improve the user interface. Of course both versions have the same features, so you're not missing out on anything if you only own one version.

The app store page is a feast for the eyes. There's a demo video (I already know how I can improve it a lot with the next update), Zebras, and lovely icy mountains.

Please share the news to help the app get traction. That would be super helpful!

Using Drag and Drop with NSTableView

Nate Thompson compiled a tutorial on how to implement drag & drop in NSTableView. It's a good read.

I remember how weird it felt to implement this the first time. Drag & drop is actually realized via the pasteboard. So it's more like cut and paste with a visual representation. From this you get the ability to put multiple content representations into the pasteboard at once, so the drop container can decide how to handle whatever it receives.

Hosting Downloads on Amazon S3 with CloudFront

Since early 2019, I host downloads for my app The Archive on Amazon's servers. The S3 bucket is a cheap-enough storage of the zip files, and the CloudFront cache is a content distribution network across the globe that improve download speeds. Here's a long tutorial, because I will most likely forget how I did all this in a while, and chances are you don't know how to do this either.

Continue reading …

Fixed the Blog Archive

I was looking for an old post and found that the paginated list of blog posts didn't quite contain all the posts I expected. Turns out I introduced an off-by-1 bug there, computing pages for 10 posts per page, but working with all_posts.each_slice(10-1), effectively dropping 1 post per page.

Of course my website isn't unit-tested, so no wonder :)

Add Navigation Buttons to NSTouchBar

Xcode and Safari sport Touch Bar items to navigate back and forth. Have a close look: When you put two NSTouchBarItems next to each other, there usually is a gap. Between the navigation controls, there is a mere hairline divider, but not the regular fixed-width space. They are not realized via NSSegmentedControl, though. Compare the navigation buttons with the system-wide controls far to the right: volume, brightness, play/pause. (I'm listening to the 1980s Pop Radio on Apple Music at the moment, in case you're curious.) The system controls are a NSSegmentedControl. They have rounded corners for the whole control, while the navigation buttons have rounded corners for every button. Also, the navigation buttons have the default button width.

Continue reading …

Do Not Apply Code Heuristics When You Need a Broader Perspective

You can only improve things inside the frame you pick. If your frame is too narrow for the problem you try to solve, you cannot properly take everything into perspective. That's a trivial statement as it's only re-stating the same thing, but it's worth stressing. Apply this to code. If you focus on code heuristics to improve your code base, you cannot improve the structure of your program. Even though the structure is manifested as code, it's not code you should be thinking about. It's concepts. Code is just the textual representation you stare at all day. Structure is what the imaginary entities of your invention bring forth.

Continue reading …

Refactoring The Archive's ReSwift Underpinnings

While I was refactoring my app's state recently, I noticed that there are virtually no dev logs about The Archive and how I manage state and events in this app. It's my largest app so far, still the amount of reflection and behind-the-scenes info is pretty sparse. This post outlines my recent changes to the app's state. It's a retelling of the past 5 weeks or so.

Continue reading …

Replace RxSwift View Model Types with Free Functions

Instead of writing view model types that expose the input and/or output ports as properties, consider writing free functions that are the transformation. This reminds me of Ken Scambler's proposal to get rid of test doubles through side-effect free function composition. One of his examples, simplified, goes like this: Instead of testing what customer.pay(amount, wallet) does in your tests by mocking the wallet object, you rewrite Wallet as a value object and change pay to return the effect.

Continue reading …

Programmatically Add Tabs to NSWindows without NSDocument

The Cocoa/AppKit documentation is very sparse when it comes to tabbing. You can make use of the native window tabbing introduced in macOS Sierra with a few simple method calls, though. Conceptually, this is what you will need to do: However, there are some caveats when implementing these methods naively. The plus button may stop working (no new tabs are added when you click it) and all default shortcuts are broken, their main menu items greyed out.

Continue reading …

NSAppearance Change Notifications for Dark Mode and RxSwift Subscriptions

Last year, I had a full-time job from May until November and haven't had much time to prepare for Mojave. Then it hit hard, and I am still tweaking my apps to look properly in Mojave's Dark Mode. I welcome that macOS offers two modes now, .aqua and .darkAqua in programmer parlance. Because then I don't have to implement a homebrew solution in all my writing applications.

Continue reading …