Parse Boolean Search Expressions in Swift

Ever wanted to implement a full-text search in your app? Didn’t find a boolean search expression parser that works? Look no further! For the initial release of my note-taking app The Archive I had to create a couple of open source libraries that I have yet to talk about. Today, I want to show you my search expression parser. It powers the app’s Omnibar to find notes quickly using simple boolean expressions.

Continue reading …

Fixing Ruby ncurses Unicode Character Display on Linux Terminals

A little side-project of mine is a role-playing game written in Ruby that runs in the terminal and uses Unicode/ASCII characters instead of bitmap pixel graphics. In my personal tradition of these kinds of side projects, this is called TermQuickRPG. It’s a work-in progress, so there’s not a lot to do in the sample game at the moment.

Continue reading …

How to Fix fileReferenceURL() to Work with NSURL in Swift 3 and Swift 4

I am upgrading the code base of the Word Counter to Swift 3. Yeah, you read that right. I didn’t touch the Swift code base for almost 2 years now. Horrible, I know – and I’m punished for deferring this so long in every module I try to convert and build. One very interesting problem was runtime crashes in a submodule I build where URLs were nil all of a sudden. This code from 2015 (!!) used to work:

Continue reading …

Remove Trailing Whitespace in TextMate 2 Code Files

I still use TextMate for some things: editing documents quickly, scripting in Ruby, navigating project folders of foreign code bases (especially when they’re not using my main language so I could use Xcode, e.g. Java projects), and finding and replacing text. But it always bugged me that when I move around code and indent and outdent and whatnot, that sometime lines with nothing but whitespaces would be saved. Or I’d combine stuff and have 10 trailing spaced all of a sudden. I do show invisible characters, but I don’t want to pay attention to that kind of stuff when I’m coding.

Continue reading …

ReSwift Custom Diffs and Enqueued State Updates

Vinh Nguyen found that his ReSwift status updates became slow.

  1. There were too many subscribers.
  2. Objects would react to state updates by dispatching a new action immediately. (ReSwift action dispatching happens synchronously.)

His app state ends up containing a lot of objects in a 3-level hierarchy that mimicks the hierarchy of view components on screen. In a drawing or otherwise canvas based graphics app, it seems. It doesn’t make sense to have each objects on the canvas responds to state updates when one other object updates on screen. Instead, you’ll want to at least minimize the amount of updates that get passed through.

Vinh implemented a custom diff or “delta update” for the 2nd level in his 3-level hierarchy of objects because they were few enough to be performant during state updates, and could easily manage their child objects.

Read about his discovery of state update bottlenecks on his blog.

He solved the second problem, newState callbacks triggering the dispatch of another action, by enqueuing the dispatch in an asynchronous block on the main queue, which is the queue ReSwift uses:

class ObjectView {
    func newState(state: ObjectState) {
        // ...
        if conditionThatTriggersAnAction == true {
            DispatchQueue.main.async {
                store.dispatch(Action())
            }
        }
    }
}

Sure, this enqueues the action dispatch until the current execution is finished. But you have to take care about other actions being dispatched in between now, and if that is a problem. (E.g. another subscriber type reacting to the same state update with another action.)

I had prefered another solution initially: subscribe to updates in the top level Canvas object, then delegate down the view hierarchy as needed. Every sub-component that wants to fire an action tell the Canvas about this, which enqueues the actions, and then processes the queue after all sub-component updates are finished. A bit like in game development where the game loop ensures there is just 1 point of action handling per run. But then again, Vinh’s approach does exactly that: it enqueues action dispatching until later, ensuring the current run loop run isn’t interrupted. Also, my approach to delegation would make everything just so much more complicated in the app code.

I wonder is it’d be beneficial if the ReSwift store operated on a high priority queue that is not the main queue all the time. Then you can dispatch actions synchronously from view components on the main queue, waiting for the result, or asynchronously.

I will have to think more about the consequences of an approach like this before I suggest anything to anybody, though. I don’t do a lot of concurrent programming in my apps, and when I do, I contain it very strictly; on the downside, I don’t have developed any instinct regarding implications of using multiple queues.

Synchronize Scrolling of Two (or More) NSScrollViews

You can make two NSScrollViews scroll in concert quite easily because every scrolled pixel is broadcasted to interested parties. In TableFlip, the main table is a NSTableView contained in a NSScrollView. You can view and hide row numbers in TableFlip; but I didn’t want to reload the whole table and mess with the table model to insert and remove the first column. Instead, I use a second table view with a single column. The upside of this approach: I can animate hiding the whole scroll view with the row numbers inside easily without affecting the main table.

Continue reading …

NSTextField usesSingleLineMode Stops Working When You Implement NSTextViewDelegate Methods

Today I learned why my NSTextField permits pasting of newline characters even though I set usesSingleLineMode properly. It’s because I made it conform to NSTextViewDelegate to cache changes. When you edit text inside of an NSTextField, you actually type inside a field editor of the window. That’s a shared NSTextView instance. Most of the hard work of an NSTextField is done by its cell, which is an NSTextCell. NSTextCells implement at least the delegate method NSTextViewDelegate.textView(_:shouldChangeTextIn:replacementText:) – and when you set usesSingleLineMode, this is actually set for the cell, not the view itself. You can use textView(_:shouldChangeTextIn:replacementText:) to sanitize input text, and I suspect that’s where the usesSingleLineMode implementation happens. If your NSTextField subclass implements this method, the NSTextCell implementation isn’t called. And since that one isn’t public (it was called “implicit protocol conformance” back in the day), you cannot delegate up in Swift because the compiler knows it isn’t there.

Continue reading …

Format Strings with Templates in Swift

Gordon Fontenot published his StringTemplate library the other day. You can use it as a much better number formatter, for example:

  • “5125550001” is your user input
  • “(XXX) XXX-XXXX” is your template
  • “(512) 555-0001” is the result of applying the template

There are options to ignore overflow or crop the remainder when only inserting part of the required digits. I think that’s pretty slick!

Panic’s New Pricing Model for Transmit on the Mac App Store

WWDC people noticed that Panic Inc. are coming back to the Mac App Store with their beloved file transfer app, Transmit. This puzzled a lot of people because they moved away from the MAS starting with Coda 2.5 in 2014. Sandboxing was just too restrictive. But now, it seems, the new Mac App Store’s Sandboxing rules will be different enough for Transmit to work. See Panic’s tweets on the topic. The details:

Continue reading …

Programming Does Not Grow Up

Watched Robert “Uncle Bob” Martin talk about “The Future of Programming” and wholeheartedly recommend it. In the talk, Uncle Bob brings up interesting points about the growth of the programming profession:

  • Roughly every five years, the number of programmers double.
  • Conversely, half of the programmers at any point in time have less than 5 years of experience.
  • The industry lacks an appropriate amount of teachers, so all the new people will make all the same mistakes over and over again.

Programming does not grow up this way. On top of that, programmer mistakes in everyday devices now are causing lethal damage to real people. Self-regulation inside the profession (which, like traditional crafts, I guess could reduce the onslaught of newcomers) and proper teaching are essential to keep growing and making code more reliable a foundation of modern societies.

That’s part of why I write, too. Because I found it was extremely hard to learn creating applications properly, not just hacking together something that barely works. I want everyone else to have a head-start compared to me. While educating myself, I discovered ancient wisdom in books from the 1970s – stuff you can still tell (or should I say: sell) people today, like how to decouple parts of your system. As if we, as a profession, suffer from collective amnesia. Old wine in new skins.

Now that I know some rough estimates about programming’s exponential growth, this makes sense. There just isn’t enough time and care put into teaching these practices properly. It’s hard enough to equip students with sufficient knowledge to become somewhat dangerous in front of a programming environment. The rest then is delegated to on-the-job training, which I imagine is pretty disappointing for all parties involved.

Add Blog Post Text Template Expansion to Emacs with Org Babel

In my quest of total immersion into Emacs, I am trying to write blog posts in Emacs instead of TextMate. That means my TextMate macros are gone for good, including insertion of YAML header information. On this very blog and on Zettelkasten.de, I used to type cthead and zkhead respectively, then expanded the YAML header with tab. TextMate’s great template feature even allows you to specify multiple points inside the templates to jump to by tabbing forward. Emacs works a bit differently, so I adapted the templates to request information up front instead and fill in the values.

Continue reading …

Bye, Bye, Google Analytics

Happy GDPR day! With the recent EU law stuff taking effect, I reconsidered my use of tracking information from you. So I just removed Google Analytics tracking on this website, on our productivity blog at zettelkasten.de, and on all my app websites completely. I find the numbers interesting, but not actionable anyway. I don’t do A/B testing. I just write for fun and with the intent to help you do stuff. There’s no benefit in tracking how you use my site. Your visit is much appreciated, and that’s it!

Continue reading …

Indent Code and Lists by 4 Spaces in Emacs Markdown Mode

I noticed that my Emacs didn’t maintain the current line’s indentation when editing code blocks in Markdown (markdown-mode). I indent the first line with 4 spaces like any sane person would. When I hit enter to continue in the next line, thanks to the markdown-mode defaults, I am presented with a new line that’s properly indented visually. Only when committing to git did I notice that Emacs inserted tabs instead of spaces. Gasp!

Continue reading …

Global TODO Capture Hotkey for Emacs Org Mode on macOS

I am using GNU Emacs for a while now to do all kinds of stuff. I’m thinking about migrating away from OmniFocus as my task manager and use Org mode instead. What I like so far is the free-form list nature of Org files. I can have an outline of notes and sprinkle TODO items inside them. This way I can take notes on puzzling problems I’m working on and mark things I need to do later. This is super useful to remind myself what to clean up before a commit, for example write or amend tests or remove debug code somewhere. I like it. I got used to a lot of shortcuts already, so most of the pain of daily use is gone.

Continue reading …

RxSwift: Typing/Idle Event Stream for NSTextView

To improve my note editing app The Archive’s responsiveness, I want to find out when the user is actively editing a note. Here’s how to create the idle switch in RxSwift/RxCocoa. A simple enum of .typing and .idle will do for a start. Of course, NSTextViewDelegate provides a textDidChange(_:) callback to hook into; it’s based on a notification, so you can also subscribe to the NSText.didChangeNotification directly if you don’t want to use a delegate. That’s the input signal I’m going to use.

Continue reading …

Broken Help Menu Breaks Rather Unpredictably

Last week, I wrote about the Help menu bug that seems to “freeze” apps inasmuch as it makes them not handle any keyboard input. The thing is, I cannot always reproduce this issue. I rebooted my system and just couldn’t break the behavior anymore. Which sounds an awful lot like running the system for a while and using it in a specific way might affect the Help menu’s behavior. But I don’t know which steps you need to take to reproduce this. It’s puzzling me. With Daniel Jalkut and a beta tester of my latest app having experienced the same issue, I know I’m not alone. Or crazy. Just clueless.

Continue reading …

Plain Controllers to Ease the Burden of View Controllers

I like to see that Soroush and I think among the same lines. For one, that makes me feel less like a loony. And since he writes a lot more in recent months, it means my sloppy blogging schedule does not affect spreading ancient wisdom. In February, Soroush blogged about writing “Just Controllers”: service objects, usually reference types, that you use to orchestrate processes and offer a simpler API. Requiring a delegate to be plugged-in is one way to design a simpler API: the delegate procotol defines all the output events from the service object, or controller. That’s all there is going to happen as far as outside code is concerned. But on its inside, the controller can do the fanciest of things to accomplish its goal. These implementation details are hidden from code that uses these service objects. It’s object-oriented programming 101 all over again – encapsulation, information hiding, stuff like that. But, and this is a big But, the go-to massive view controllers in iOS apps are a symptom of not encapsulating properly. Go and delineate a few more boundaries inside your app. As with raising children, boundaries help your code grow properly, too!

Put Test Files Next to Production Code for Better Discoverability?

The Kickstarter engineering team posted an interesting proposal: put your XCTestCase files into the same directory and group as your production code. Do keep the separate target ownership, of course.

One clear benefit is directory tree or file management, and discoverability of tests for people browsing the code: In most cases, you have FooService in FooProject/FooApp/FooService.swift, and FooServiceTests in FooProject/FooAppTests/FooServiceTests.swift. With nested folders, you need to navigate around even more. I got used to this Xcode default. But I also got annoyed by this split at the root level when I browsed code on GitHub. Multiple tabs in a modern browser to the rescue, this was never that problematic, given the test directory is structured in a similar way. If not, good look finding the file you’re looking for. (I hate that the RxSwift project, which I often had to browse to look up an implementation detail, has files that contain only a path reference to the real file, similar to ../../Core/SomethingSomething.swift, making tests pretty hard to find).

I will try this approach with a library module that I develop as a sub-project of The Archive and report back.

High Sierra: Help Main Menu is Broken and Freezes Apps

If you run macOS 10.13 High Sierra, try not to use the Help menu. It will appear to freeze the app for which you invoke the Help menu: it will not accept keyboard input anymore, emitting the NSBeep “invalid action” sound in most circumstances. The reason seems to be that the nifty Search bar inside the Help menu will acquire focus so you can search for a menu item or help book entry. This is taking away focus from the app window. You notice this when the blue focus ring around an active text field in the window goes away; instead, the Help menu’s Search bar obtains focus and the accompanying blue focus ring. All this is supposed to happen. This process just isn’t reverted for some reason since at least macOS 10.13.3, maybe earlier. When you click back into the app outside of the Help menu, the key window status will not be assigned back to the window you click on. That means keyboard input will not work at all. (As a non-native English speaker, I asked if “key window” was supposed to mean “window that responds to key events” a while back. While people agreed this wasn’t the intention, I still cannot help to think that way. The app has no key window, so key events are not handled, resulting in NSBeep.)

Continue reading …

A Visually More Accessible Disabled NSColorWell

I use the macOS color well to let users of The Archive tint vector icons in their favorite color. But setting NSColorWell.isEnabled hardly produces a visual change in the color editor. Can you easily tell which is enabled and which is disabled if it weren’t for the checkbox? The little frame color change is too subtle for my taste. I added a high-contrast strike-through line to my color well:

Continue reading …

The Archive Is Available Now

Teaser image

My next macOS app project has launched: It’s a note-taking app for macOS to help writers write more. In our typical German stoic way, we just call it The Archive. Check out The Archive! Its choice of features is closely tied to a few core principles: the user is more important than your app; plain text comes first, so avoid proprietary features and vendor lock-in, thus furthering replicability of the workflow in other apps. I guess we’ll write more about that in the future.

Continue reading …

NSTextView’s Default Insertion Point and Selected Text Colors

Teaser image

NSTextView can be customized to display different colors for the insertion point (aka caret, aka text cursor) and for selected text. This is especially useful when you add themes to your editor and the default settings don’t fit anymore. The default values are not exposed anywhere, so I had to log them and reconstruct convenient accessors to reset a text view if needed:

Continue reading …

Launch of My Next App, The Archive

Teaser image
screenshot of The Archive

I spent the last 15 or so months developing this beast. If you follow my ramblings, you will know that I get to work every day at about 7 a.m. and work until about 5:30 p.m., including workouts and breaks. Since I didn’t use a time tracker like Timing (affiliate link) for most of the time, I cannot say how many hours I really spent coding, sadly.

Anyway. The launch. The Archive will go live March 15th. I’ll publicize the app info page, soon.

And then I’ll spend some leisure time writing a postmortem. The beta testers have been a pleasure to work with, as always. It’s amazing how much love strangers are willing to give for carefully crafted products.

This closes a weird circle for me: my first Cocoa coding experience was adding Markdown preview to Notational Velocity in 2010, which I barely managed, having had zero understanding of Objective-C and how Xcode worked. Now I am able to create an app that exceeds NV’s capabilities all on my own. I’m very happy about this coding journey, and oh boy do I have a lot of cool stuff I am going to add after v1.0 goes live!

How I Avoided Over-Architecting a Simple Event Handler with ReSwift, Cheating with Existing Reactive Code

I am using ReSwift in my app. I like ReSwift because I can create a representation of my app in a “State” Swift module without any UIKit/AppKit dependency. There, I put all the data that the app is supposed to represent at any given moment in time. To get a feeling for this, have a look at two apps of mine:

Continue reading …

Behind the Scenes of Programming ‘The Archive’: How Much Coffee Did I Consume?

When I announced the imminent launch of my latest app project, The Archive, a beta tester asked how many jars of coffee I consumed while coding. “Jar” is no mistake. I drink from a 750ml glass jar, full to the brim. That’s one portion of cowboy coffee, or is it turkish coffee? – I’m not quite sure what to call it: grind the beans, pour water, stir from time to time, let it settle, then drink.

Continue reading …

NSTextView: When Did the Find Bar Disappear?

For whatever reason, my current app project’s find bar does not make the text view firstResponder again when you hit Escape or click the “Done” button to close it. This is very uncomfortable for users: they type away, hit ⌘F to find a phrase, then hit Esc – and now they’re in limbo. To my astonishment, the NSTextFinderAction called hideFindInterface is not triggered when you make the find bar disappear. Its opposite, showFindInterface, is triggered when the find bar slides back in, though. Intercepting in NSTextView.performTextFinderAction(_:) does not help, then.

Continue reading …