Mac Text Editing: mark, kill, yank

I’ve been implementing the mark, kill, and yank actions for Bike Outliner. These actions are obscure and under documented. This post documents what I’ve found and includes code I used to implement them.

My understanding is that these features were originally implemented in terminal based editors. Later used by NeXTSTEP. Now many years later they are still with us on macOS.

There isn’t much documentation of the macOS implementation. Much of the following behavior was discovered by experimenting with TextEdit. Probably I’ve missed some things and got some things wrong.

Corrections welcome!

Mark

Marks are from terminal editors where it wasn’t possible to visually select a range of text. When you needed to define a range you would “mark” one end and use the insertion point for the other.

Actions to manipulate the mark:

Note that on macOS the mark is a range, not a single point. The mark shouldn’t be updated to account for text changes in the editor. When reading the the mark always clamp it to the editor’s text length.

I don’t think there are standard keybindings for mark actions. I think they are mostly used when building up more complex multi-action keybindings. See the keybinding links below.

Kill

When text is deleted by certain actions it gets added to the kill ring. By default the kill ring contains a single text entry. If you change the NSTextKillRingSize system default the kill ring can contain multiple entries.

Actions that kill text:

Generally killed text it is added to the ring as a new entry. Once the ring is filled it will wrap and new kills replace older kills.

The exception is when you repeat the same kill action. In that case the killed text is combined with the current kill entry. This coalescing stops when you edit text or change the selection.

To quickly try out kill use:

Yank

Text can be retrieved from the kill ring by yank:

Each app maintains a private kill ring. You can kill text in one view and then yank it into another view within the same app. You can’t kill or yank between apps.

To quickly try out yank use:

Why would you use these actions?

I have seen these actions used most often in custom multi-action keybindings. Marks are useful for saving and restoring the selection. Kill and yank are useful for moving text without overwriting the pasteboard.

To learn more about keybindings:

How to implement in your own text editor?

I’ve created KillRing.swift class to get you started.

The kill ring needs to maintain some state. Your editor should call selectionChanged() and textChanged() anytime they change in your editor. When killing and yanking your editor should perform all related changes within the callback block.