What’s the diff?

This morning’s post by John D. Cook brought up an interesting problem: what’s a good way to check for differences between files when the files consist of just a few (or maybe just one) very long lines?

The problem is that diff, the standard Unix tool for finding differences, tells you which lines are different. This is great for source code files, which are written by human beings and in which the lines tend to be short, but not so much for machine-generated files like JSON, XML, and some HTML files, in which line breaks may be few and far between.

Cook’s solution for comparing long-lined files is to pass them through fold before sending them to diff:

diff <(fold -s -w 20 temp1.txt) <(fold -s -w 20 temp2.txt)

The -s option tells fold to break at space characters instead of in the middle of a word. The -w 20 option tells it to make the new lines no more than 20 characters long. Breaking the text into lines of only 20 characters is overkill, but it certainly is easy to see differences between lines when you have only 20 characters to scan through.

The <() thing is a bit of clever shell scripting known as process substitution. It’s used instead of piping when you have more than one input that needs to be fed to a command.

I was unfamiliar with fold until today. Whenever I’ve needed to reformat a text file to a given line length, I’ve used fmt. What I like about fmt is that it defaults to breaking lines at spaces—no need for the equivalent of the -s option. So I’d do

diff <(fmt temp1.txt) <(fmt temp2.txt)

if I were OK with fmt’s default line length of 75 characters, or

diff <(fmt -20 temp1.txt) <(fmt -20 temp2.txt)

if I wanted to use Cook’s extremely short lines.

But I’d be even more likely to open both files in BBEdit and use its Search▸Find Differences▸Compare Two Front Windows command. That would give me this nice two-pane output:

BBEdit differences

In this example, there’s only one line, but it’s broken into easily digestible pieces by BBEdit’s soft wrapping, and the exact spot at which the difference occurs is highlighted by the darker purple background.1

There is a diffing app called Kaleidoscope that I’ve heard good things about, but I’ve never felt hampered by BBEdit.


  1. In his example text, Cook punned by changing Melville’s “hypos” to “typoes.” Not to be outpunned, I changed it to “typees.” 


The two Johnnies

I was out running errands in the middle of the day, so I only saw the last 15 minutes or so of today’s Apple Event. But it didn’t take long to catch up.

Apple Event logo

Given the pre-event rumors and the graphic in the invitation, I don’t suppose it surprised anyone that colors came back to the iMac. I admit, though, that I was surprised at how bold the colors are, at least on the back sides.

New color iMacs

For over a year, ever since Jony Ive said good-bye, I’ve been waiting for color to return to the iMac. It seemed to me that the spare aluminum iMac, whose fundamental design has been unchanged since 2012, was Jony’s ideal iMac. Oh, I’m sure he would’ve gotten rid of the bulge in the back if it weren’t for the thickness of spinning disks and the need to cool Intel’s chips, but I think he considered the bare aluminum and glass look to be pure and honest. It’s the truest evocation of the materials used to make the device and what he’d been working toward for years. That’s why the 2012 design persisted for so long. Why mess with perfection? And who was left at Apple to tell Jony that it wasn’t perfect?

But now that it’s been a decent interval since he left, Apple’s industrial design can move on. I expect we’ll see colors leak back into several colorless product lines. I’m not sure what we’ll see in the upcoming large iMacs and more powerful MacBook Pros; Apple may still be reluctant to add anything more than anemic pastels to its “pro” line. But the MacBook Air is an obvious target. The first M1 Airs, like the one I’m typing on right now, kept the old look because it was faster and cheaper to do it that way, but I’d be very surprised if the next generation of Airs weren’t at least as colorful as what we saw in today’s small iMacs.

The other big change in the look of today’s iMacs is due primarily to someone who isn’t on the industrial design team: Johny Srouji. The iPad-like look of the new iMac is possible because of the iPad-like chip that drives it. And the size and shape of every Mac that Apple makes from now on is going to be based on parameters set by Johny’s chips. Small, efficient, and cool, those chips are going to set the boundaries within which Evans Hankey and her team will work.

I’m sure Jony is happy with his decision to leave Apple after so many years. But I suspect he sometimes looks down from his pure white realm and thinks about what he could do with Macs if he had Johny’s chips to work with.


A Drafts custom syntax for book lists

One of the things I use Notes for is to keep track of books I’ve bought and read. It works well enough but not the way I’d really like it to. I want two checkmarks for each item—one saying I own the book and the other saying I’ve read it—and Notes allows only one. My compromise is to use the real checkmark for ownership and a checkmark character (✔, the Unicode heavy check mark) for read status after the title.

Book list in Notes

The obvious downside to this compromise is that I have to set the cursor after the title and then type in the second checkmark. If it were a real checkmark, I could just tap it.

Recently, David Sparks made a video about using Drafts for lists. While I was watching it, I started thinking about using Drafts for my book lists. Drafts now allows custom syntaxes and themes, so it seemed likely I could start with the Simple List syntax and rewrite it to fit my needs.

After a bunch of trial and error, I got more or less what I wanted:

Book list in Drafts

The theme is not yet in final form—I’m still experimenting with line spacing and font sizes—but the syntax is working well. I can now tap to toggle both the owned and read status.

The syntax rules are very simple:

  1. If a line starts with any character other than a ○ (Unicode white open circle), a ◉ (Unicode fisheye), a space, or a newline, it’s a heading.
  2. If a line starts with a ○ or a ◉, it’s a list item.
  3. The ○ and ◉ characters act as checkboxes wherever they appear in a line. Tapping on one toggles to the other.

Here’s the custom syntax definition:

 1:  {
 2:    "name": "Media List",
 3:    "description": "Checklist for books, movies, etc. Checkbox before title indicates ownership; checkbox after title indicates completion.",
 4:    "sampleText": "Media List\n\n○ Not owned or completed ○\n◉ Owned but not completed ○\n◉ Owned and completed ◉",
 5:    "author": "Dr. Drang - adapted from Simple List",
 6:    "scopeName": "text.medialist",
 7:    "rangeExtensionType": {
 8:      "default": "lineExtended"
 9:    },
10:    "listCompletionDefinitions": [
11:      {
12:        "comment": "",
13:        "enabled": true,
14:        "match": "^( *)(([\\u25CB\\u25C9]) )(.*)",
15:        "captures": {
16:          "indent": "1",
17:          "prefix": "2",
18:          "line": "4",
19:          "sequence": ""
20:        },
21:        "replacements": {
22:          "◉": "○"
23:        }
24:      }
25:    ],
26:    "fileExtensions": [
27:    ],
28:    "patterns": [
29:      {
30:        "match": "^([^\\u25CB\\u25C9 \\n].*)$",
31:        "exclusive": true,
32:        "comment": "Heading or title",
33:        "captures": {
34:          "1": {
35:            "scope": "text.heading"
36:          }
37:        }
38:      }
39:   ],
40:    "navigationPatterns": [
41:      {
42:        "match": "^([^\\u25CB\\u25C9 \\n].*)$",
43:        "rangeCapture": "0",
44:        "comment": "Header or title",
45:        "prefix": "Header",
46:        "labelCapture": "1",
47:        "identifierCapture": "1",
48:        "level": 0
49:      }
50:    ],
51:    "taskMarkDefinitions": [
52:      {
53:        "enabled": true,
54:        "match": "([\\u25CB\\u25C9︎])",
55:        "comment": "Checkboxes",
56:        "rangeType": "task",
57:        "captures": {
58:          "interactive": "1",
59:          "state": "1"
60:        },
61:        "states": [
62:          "○",
63:          "◉"
64:        ],
65:        "scopes": {
66:          "interactive": "text.checkbox"
67:        }
68:      }
69:    ]
70:  }

I started with the Simple List syntax file, altered the definitions in the heading, navigation, and task mark sections, and stripped out everything else.

I’m not saying that building a custom syntax is easy, but it is relatively straightforward if you read the documentation with one of the built-in syntax files open in front of you. The main things I had to remember were to double the backslashes (a common requirement when strings are interpreted in two stages) and to use Unicode hex codes (\u25CB and \u25c9) within the regular expressions and the characters themselves (○ and ◉) elsewhere.

As for the theme, I made a copy of the built-in Light theme, changed the color of headings to black (I dislike the brownish purple headings of the Light theme) and added a section for the new text.checkbox scope:

"text.checkbox": {
    "name": "Checkbox Text",
    "settings": {
        "fontWeight": "normal",
        "fontSize": "normal"
    }
},

At present, this scope is sort of a placeholder. It’s basically the same as the text.normal style, but it gives me the ability to alter the style of the checkboxes in the future without changing the syntax.

You’ll notice that the checkboxes in the screenshot are blue even though there’s no such color specification in the theme. I think that’s because clickable text in Drafts is always blue. According to the documentation, the foreground color of a task mark cannot be changed. Maybe in a future version.

One last thing. The ○ and ◉ characters may appear quite different in size here in the blog, but they are the same size in Drafts. Do I know why? No. I do know that I chose those two characters because my original choices, ☐ and ☑︎, were different sizes in Drafts, and when I tapped to toggle between the two states, the different sizes for those characters caused the line to jump up or down. I didn’t like that, so I switched from boxes to circles.1

I suspect the character size differences are due to some sort of font substitution going on behind the scenes, but I don’t feel like digging into the problem.


  1. Although I keep calling them checkboxes


A keyboard experiment

As soon as I unboxed my new MacBook Air, I knew there’d be one problem I’d have to get around: Apple had assigned a special action to every function key.

MacBook Air function keys

Every Mac keyboard I’d used before this one had some empty function keys in the middle of the row. And for at least a decade, I had mapped one of them, F5, to the Show Desktop action. The Desktop is a convenient spot to save temporary files, and dragging them to and from the Desktop is most easily done when you have a simple way to show and hide all your windows while in the middle of a drag. Mapping the Show Desktop toggle to F5 gave me that simple way. And it’s become such a regular part of how I use a Mac that I was afraid I couldn’t retrain myself to use anything else.

I tried. For a couple of weeks, I had Show Desktop mapped to ⌥⌘D, but it never felt right. There’s a certain “pat your head while you rub your belly” aspect to using a three-finger keyboard combination with one hand while dragging with the other. I know it sounds silly, but the added work of arranging my left hand to press more than one key often made my right hand drop what it was dragging. Old dog, new tricks.

So this meant I had to do what I was hoping to avoid: turn on the dreaded “Use F1, F2, etc. keys as standard function keys” setting.

Keyboard settings for function keys

(By the way, has anyone at Apple read the text of this option carefully? Why would my MacBook Air’s keyboard be considered external? Even on an iMac or Mac Pro, I wouldn’t think of the keyboard that comes with the computer as external. An external keyboard is what I use when working on my iPad.)

There are two reasons I have always avoided turning on the standard function key setting:

  1. I use some of the special actions quite often, especially the volume control keys over at the right end. Using the fn key with them is inconvenient because it’s a two-handed action.
  2. It’s clear that Apple expects you to keep that option turned off, and I have learned over the years that doing things outside Apple’s expectations often leads to weird behavior.1

But I really wanted F5 to Show Desktop, so I clicked the checkbox and mapped F5 the way I wanted. That worked fine, but as I had feared, it ruined other behavior.

According to the description,

When this option is selected, press the Fn key to use the special features printed on each key.

That was true for the volume and brightness control keys, but not for Spotlight (F4), Dictation (F5) or Do Not Disturb (F6). Pressing these keys along with fn did absolutely nothing after activating the standard function key setting. So I had to work through all the settings (and do a little work in Keyboard Maestro) to get reasonable access to all the features:

I haven’t bothered remapping F1 or F2 because I very seldom change the screen brightness.

The two Mission Control actions I’ve mapped to F3 and F4 don’t get used as much as F5, but they’re very helpful in digging out buried windows, especially on a small notebook screen where there’s lots of overlap. And there’s a logic to their positioning helps me remember what they do, even for the two that don’t have their function printed on the key.

Function key actions

Was all this dicking around worth it? I think so. Hesitating over common operations doesn’t just waste time; it makes you shift your thinking back and forth between what you’re working on and the mechanical operation of your computer. Almost anything that keeps you focused is worth it.

I will feel a little foolish if someone emails me and says “Why didn’t you just do X?” and they have a way of getting F5 mapped to Show Desktop without going through all the rest of this nonsense. But if there is an easier way, I’ll happily adopt it.


  1. This isn’t just an Apple thing. I’ve found certain settings mess up Windows, too, because Microsoft just didn’t test their behavior as thoroughly as it did the more standard parts of the OS.