WordCounter v1.6.4 Released

WordCounter v1.6.4 is just released and comes with mostly Big Sur compatibility fixes and a fix for the calendar view: January 2021 in Gregorian calendars was displayed oddly, because the maths for the week calculations accidentally produced January 2022 and not 2021. Calendar arithmetics are still hard.

Quality of life improvement: you can now see the year in the calendar view, both in the labels for the month and in the daily details.

For all of you waiting for character counts: I’ll be working on that next, but will have to revamp more than you might think to not slow down the app whe accessing your data. Will take a while.

Release Notes

  • Fixed: Month of January 2021 displayed completely wrong with Gregorian (“western”) calendars.
  • Fixed: Hang-up when selecting something in the history, then scrolling down a lot, then selecting another day.
  • Changed: When exporting the stats to CSV, reveal the file in Finder.
  • New: Display years in both the History’s month view, and the daily stats.

This is a free update.

Related links:

NSSavePanel Crashes on Big Sur for public.csv UTI When You Don't Have a CSV Editor

Was working on an export sheet today and during testing on Big Sur, I noticed that the button that would bring up the save panel would produce a beachball for a while, and then I’d get an error dialog telling me that the panel crashed.

I changed the NSSavePanel.allowedFileTypes property to ["public.csv"] during this update, and that trips up the save panel on Big Sur. Note that ["csv"] works just fine.

It seems to be related to the file types being declared as an array of UTI (Universal Type Identifiers). This worked marvellous thus far, so I’m a bit confused about the crash.

From the header files:

NSSavePanel: An array of NSStrings specifying the file types the user can save the file as. The file type can be a common file extension, or a UTI.

Looking at the docs and header files, it looks like allowedFileTypes was deprecated in favor of macOS 11.0 API, allowedContentTypes. That might explain it, but it doesn’t excuse the backwards-incompatibility.

Actually, the UTI recommendation is not true anymore.

By now, I expected NSSavePanel.alloedContentTypes to work, and then to have Xcode suggest to wrap access to that property in an if-@available block. But that doesn’t work at all. With macOS 10.15 Catalina being my main dev machine, I cannot use the new API at all at the moment, it seems, no matter what I set the deployment target to. I’m using Xcode 12.3 by the way.

Meanwhile, a save panel using UTI file types works fine in TableFlip on Big Sur. I don’t know why. (I’m happy that it wasn’t broken for the past months, though.)

When I actually ran TableFlip to test this, which is an NSDocument-based app, and then tried to run the breaking sample app again, everything workes fine.


Deleting TableFlip from the Big Sur test device produced the error again.

It actually turns out that public.csv is not a built-in file type recognized by macOS. The archived docs for UTIs list many UTIs, but not CSV.

So make sure to check your assumptions when you write apps that export data without actually registering the exported file type UTIs!

Update 2021-01-21: Thanks Aaron Tuller for pointing me to kUTTypeCommaSeparatedText which has the value "public.comma-separated-values-text". That might work!

As for CSV, my personal recommendation is to make sure you register the UTI with your app and not pass file extensions instead of UTIs: in Xcode’s target settings for the app target, go to “Info” and fill in the blanks for a new UTI below “Exported Imported Type Identifiers”:

Example of how I fill in the blanks to register CSV

Update 2021-01-21: Thanks to Nate Weaver for pointing out that I should use an Imported and not an Exported Type Identifier. Here’s why, from the docs:

An imported UTI declaration is used to declare a type that the bundle does not own, but would like to see available on the system

I filed FB8974625 for the crash due to stack overflow in a self-referencing method call in AppKit’s save panel.

I don’t have a virgin Catalina computer lying around, so I cannot test if this is an old problem or just related to Big Sur. If you know of this problem on pre-Big Sur machines, let me know in the comments!

DuckDuckGo Site Search in Vanilla Forums Templates

Over at the Zettelkasten Forum, we are using a PHP forum software called Vanilla Forum“.

(Vanilla is free and open source if you host it yourself, but the creators also offer managed hosting with some additional features. I like it, it works well, and is pretty well-worn by communities all over the web.)

The default forum search is abysmal, though, so we wanted to replace it with a DuckDuckGo site-search. In most web search engines, you can use the site: prefix, as in site:christiantietze.de, to limit search results to a domain. We are already using it on the Zettelkasten main page but I couldn’t find a Vanilla plug-in in the plug-in repository to do the job.

Turns out that the default search box is implemented by adding a Smarty template engine function call. See the forum docs.

I looked at the implementation {searchbox} in /library/SmartyPlugins/function.searchbox.php. It’s implemented via the function smarty_function_searchbox – and I found out that you can add your own Smarty template functions by using the same name pattern. For {duckduckgo} I had to call my function smart_function_duckduckgo.

I put the function declaration in my themes main PHP file, the theme hooks file, at the very bottom, and that was all I had to do.

Smarty template engine function calls can have parameters. So I made the function reusable, and if you want to check it out, you can copy & paste the implementation in your template PHP file as well and tweak the parameters in your templates.

function smarty_function_duckduckgo($params, &$smarty) {
    /// Search text field placeholder value.
    $placeholder = array_key_exists('placeholder', $params)
        ? val('placeholder', $params, '', true)
        : t('SearchBoxPlaceHolder', 'Search');
    /// DuckDuckGo site-search value.
    $site = array_key_exists('site', $params)
        ? val('site', $params, '', true)
        : '';

    $form = Gdn::factory('Form');
    $result = $form->open(['action' => 'https://duckduckgo.com/?kp=-1&kl=us-en&kg=g',
            'method' => 'get', 'accept-charset' => 'utf-8',
            'role' => 'search', aria-label => 'Sitewide']).
        $form->hidden('sites', [ 'value' => $site]).
        $form->textBox('q', ['placeholder' => $placeholder,
             'name' => 'q', 'spellcheck' => 'false', 'accesskey' => '/',
             'aria-label' => t('Enter your search term.'), '
             title' => t('Enter your search term.'),
             'role' => 'searchbox', 'class' => 'InputBox js-search']).
        $form->button('Go', ['name' => '', 'arial-label' => t('Search')]).
    return $result;

In my template, I then added this:

{duckduckgo placeholder='Search Forum' site='forum.zettelkasten.de'}

Please note that single quotes work, but double-quoted values are ignored for some reason.

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

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.

I discovered Emacs’s built-in profiling package. That. Is. Amazing.

  • M-x profiler-start, select CPU usage
  • scroll in the big file for a while
  • M-x profiler-stop
  • M-x profiler-report to show the measurements

The output surprisingly reminds me of Xcode Instrument’s profiler. It’s good. You get a nested, interactive list like this:

- command-execute                                                6597  96%
 - call-interactively                                            6597  96%
  - funcall-interactively                                        6597  96%
   - eval-expression                                             6597  96%
    - eval                                                       6597  96%
     - pixel-scroll-mode                                         6597  96%
      - debug                                                    6597  96%
       - recursive-edit                                          6566  96%
        - command-execute                                        6437  94%
         - call-interactively                                    6437  94%
          - funcall-interactively                                5570  81%
           - mwheel-scroll                                       5527  81%
            - pixel-scroll-up                                    5389  79%
             - pixel-line-height                                 4442  65%
              - pixel-visual-line-height                         4442  65%
               - pixel-visible-pos-in-window                     4438  65%
                - pos-visible-in-window-p                        4430  65%
                 - eval                                          4430  65%
                  - concat                                       4311  63%
                   - projectile-project-name                     4311  63%
                    + projectile-project-root                    4311  63%
                  + doom-modeline-format--main                    115   1%
             + pixel-scroll-pixel-up                              560   8%
             + pixel-point-at-top-p                               385   5%
            + pixel-scroll-down                                   138   2%

From this I learned that projectile-project-name is responsible for 63% of CPU load during the scroll operation. That didn’t make much sense to me, because I wasn’t switching buffers, so no need to update the project name, right?

Turns out my configuration was stupid:

(use-package projectile
  ;; Remove the mode name for projectile-mode, but show the project name.
  :delight '(:eval (concat " p[" (projectile-project-name) "]"))
  ;; ...

This shortens the minor mode “lighter” (that’s the info text about which minor mode is currently active) to show p[PROJECTNAME]. Used to be Projectile, which I didn’t find very helpful.

Since the next entry in the scrolling callbacks at that point is doom-modeline-format--main, I assume that during scrolling, the modeline (aka status bar) updates continuously, e.g. to display the current line and column of the cursor position, and the % I have scrolled, and such things. And that modeline update apparently also requests the project name over and over and over and that’s kinda slow, it seems?

I would’ve expected a stack trace/call tree of modeline-update-sth-sth first, but the educated guess here still paid off: I removed the lighter completely (just :delight, no arguments) and am now enjoying butter-smooth scrolling for the most part.


Also, very cool that Emacs is in fact a Lisp engine, and that everything that happens inside the editor is part of the program, so you can inspect and customize and profile it. That was super helpful!

My first attempt, by the way, was to load 50% of my configuration file and then see how performance was. Essentially like git bisect, aka “I don’t know what’s going on and am mechanically narrowing down the source of the problem step by step”.

With profiling, you leave the guessing game behind completely and get really useful, focused data. I recommend adding this to your toolset.

See also:

Uberabout Makes Your App's About Window More Sexy

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!

Pulse to Highlight Yanked Text in Vanilla Emacs

I somehow found Abin Simon’s post about how he made pasting text in his Emacs “pulse”, aka temporarily highlight the pasted region.

In Emacs parlance, pasting is called “yanking”. His post sadly covers only one use case: Emacs with evil-mode, which adds vim keybindings and apparently also adds a special evil-yank command in place of the regular yank.

Update 2020-12-21: Abin pointed out to me that “yanking” in vim parlance means the exact opposite – copying! What is happening in this world?! Anyway, he pointed me towards goggles.el, a package that does the same effect as the code below, and then some. Check it out!

The evil Emacs version is easier to make pulse-to-highlight because its function parameter already define the beginning and end position of the yanked text. These two parameters are then passed on to pulse-momentary-highlight-region. The pulsing highlight is built-in, but to adapt the stuff to work with the regular pasting-aka-yanking, I had to change things up a bit.

Most basic highlight fading from yellow to white in action, using colors from the modus-themes

For vanilla Emacs yank, I used the Decorator Pattern (called “advice” in Emacs Lisp) and captured the point (row & column in the text of the insertion point) before and after the paste:

(require 'pulse)
(defun ct/yank-pulse-advice (orig-fn &rest args)
  ;; Define the variables first
  (let (begin end)
    ;; Initialize `begin` to the current point before pasting
    (setq begin (point))
    ;; Forward to the decorated function (i.e. `yank`)
    (apply orig-fn args)
    ;; Initialize `end` to the current point after pasting
    (setq end (point))
    ;; Pulse to highlight!
    (pulse-momentary-highlight-region begin end)))
(advice-add 'yank :around #'ct/yank-pulse-advice))

Markdown Mode Fixes Imenu Tag Generator

I installed Treemacs the other day and found out, to my excitement!, that you can not only hit TAB to expand folders, but also to expand files! When you “expand” a Markdown file, you see its headings in the file explorer. That is bonkers, and so useful for larger writing projects to get a unified overview!

I’ll definitely write more about this once I figure out how to make the setup simple and appealing enough to emacs newcomers.

In that process I noticed that for my blog here and on zettelkasten.de I’m using YAML frontmatter for the page title, and then level-2 headings to add structure to the document. This produced a bug in the generated outline. That’s not Treemacs’s fault, though, it was a bug in markdown-mode regarding the outline generation. The outline is represented as “imenu tags”, whatever that means in detail.

After I figured this out and reported an issue, it took only 3 days for a fix to arrive.

Consider this to be a little ad hoc love letter to Open Source.

If you’re an emacs user, I’d like to encourage you to check out markdown-mode from GitHub and play with Treemacs for a while.

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.

→ Blog Archive