![]()
12 Oct 2026
Textee is my own text editor for macOS. It replaces TextMate, and its main job is the clipboard scratchpad: I type ca in Alfred, and the clipboard lands in a new text file, in a Textee tab, a fraction of a second later.
It's the sibling of Notee: my own Markdown editor for macOS, which replaced VS Code for my Markdown notes. Same family of -ee apps, same way of building them (The era of personal software is here), but no shared code: each app is optimised for its 1 job.
The code is public on GitHub: ndeville/textee, under the MIT licence. Anyone with a Mac and Xcode can build it.

Why I built it
Before writing a line of code, Claude analysed how I actually used TextMate. The answer surprised me: TextMate was mostly a clipboard dump.
- The Alfred keyword
cawrote the clipboard to~/txt/YYMMDD-HHMMSS.txtand opened it in TextMate. That folder held 3,144 files since April 2025, about 8 a day. - 95% of those files never changed after the first hour. Read once, keep for search.
- 24% contained Markdown, mostly LLM answers I pasted to read or edit.
- I had 2 workarounds for things TextMate didn't do: a rebound word count command, and a Hammerspoon overlay that drew a character count on the TextMate status bar every 0.5 s.
- TextMate's Edit > Paste is a submenu, which broke my global Copy (⌘D) and Paste (⌘F) remaps.
TextMate is still a good, native editor (TextMate). But development has slowed, and I wanted the scratchpad to work exactly the way I use it.
What it does
The full list, as of 15th October.
Scratchpad
| Feature | How it works |
|---|---|
| Clipboard scratch | ca in Alfred (or ⇧⌘N) writes the clipboard to ~/txt/YYMMDD-HHMMSS.txt and opens it in a tab |
| New scratch file | ⌘N creates an empty timestamped file. If it's still empty when I close the tab, it's gone |
| Auto-save | 1 s after I stop typing, on a tab switch, when I switch apps and on quit. No Save dialog |
| Tabs | 1 window, 1 tab per file. Each tab keeps its own editor, so switching is instant |
| Counts | Line and column, lines, words and characters, and the same for the selection |
| LinkedIn count | Green up to 300 characters (an invitation note), amber over 3,000 (the post limit) |
Editing
| Feature | How it works |
|---|---|
| Multiple cursors | ⌥↩ adds the next match, ⇧⌘A selects every match, ⌥-click adds a cursor, Esc goes back to 1 |
| Line commands | ⌘T duplicates, ⌥D deletes the line (as in VS Code), ⌥↑ and ⌥↓ move it, ⌘] and ⌘[ indent |
| Plain text | Copy and paste carry no formatting. 3 cursors and 3 lines on the clipboard: 1 line per cursor |
| Indentation | Return keeps the indent. Tab inserts 4 spaces, or indents the selected lines |
| Markdown bold | ⇧⌘B wraps the selection in ** |
| View | Soft wrap (⌥Z), line numbers, current line band, zoom (⌘= ⌘- ⌘0), all kept between launches |
| Selection | A strong blue, the same as the status bar, so a selection is clear on the dark theme |
Colours
TextMate's Blackboard theme, for 5 formats. Textee colours only the lines on screen, and the next ones when I scroll.
| Format | Coloured |
|---|---|
| Markdown | Front matter, headings, bold, italic, code, fences, links |
| JSON | Keys, strings, numbers, true/false/null, comments |
| YAML | Keys, strings, scalars, anchors, comments |
| Python | Keywords, strings, decorators, function and class names |
| Shell | Keywords, builtins, strings, variables, comments |
Markdown in a .txt scratch file stays plain, and files over 5 MB aren't coloured.
Find and open
| Feature | How it works |
|---|---|
| Quick open | ⌘P (or ⌘H) searches recent files and all of ~/txt by name, first line and content |
| Find and replace | ⇧⌘F: match case, regex with $1 templates, every match coloured, "2 of 16", All as 1 undo |
| Open in Notee | ⌥⌘O hands a file to Notee when it deserves a real Markdown workspace |
| Reveal and copy path | ⌥⌘R shows the file in Finder, ⇧⌘D copies its path |
Safe saving
| Feature | How it works |
|---|---|
| Atomic saves | The file is replaced in 1 step and keeps its metadata, its line endings (LF or CRLF), its BOM |
| Changes on disk | A file another app changed reloads by itself. With unsaved edits, a banner asks which to keep |
| No accidents | Auto-save never writes an empty buffer over a file with content |
| Read-only | A file that isn't valid UTF-8 opens read-only, with a banner, so Textee can't damage it |
Settings
~/.textee/settings.json holds 2 settings. I edit the file, and Textee applies a save at once, with no restart. All my apps share the same 2 keys, starting with Filee: my own file manager for macOS, so I can compare square and rounded corners across them.
| Key | Values | Default | Sets |
|---|---|---|---|
windowCorners |
"rounded" or "square" |
"rounded" |
The window corners and shadow |
cornerRadius |
0 (square) to 10 | 4 | The tab highlights, the close button, quick open |
Mine is set to square and 0. macOS 26 has no public setting for square windows: Textee answers a private AppKit method, _cornerMask. If a later macOS stops asking, the window stays rounded and nothing else breaks.
Keys
The menus use the standard titles, so my own App Shortcuts apply. ⌘D for Copy and ⌘F for Paste are my global remaps.
| Key | Command | Key | Command |
|---|---|---|---|
| ⌘N | New scratch file | ⌘D | Copy |
| ⇧⌘N | New from clipboard | ⌘F | Paste |
| ⌘O | Open… | ⌥F | Paste and match style |
| ⌘P / ⌘H | Quick open / recent files | ⇧⌘F | Find… |
| ⌘S | Save now | ⌃F | Hide the find bar |
| ⌥⌘S | Save as… | ⌘T | Duplicate line or selection |
| ⌘W | Close tab | ⌥D | Delete line |
| ⌃⌘W | Close window (every tab) | ⌥↑ / ⌥↓ | Move line |
| ⌥⌘O | Open in Notee | ⌘] / ⌘[ | Indent / outdent |
| ⌥⌘R | Reveal in Finder | ⌥↩ | Add next match |
| ⇧⌘D | Copy the path | ⇧⌘A | Select all matches |
| ⇧⌘] / ⇧⌘[ | Next / previous tab | ⇧⌘B | Markdown bold |
| ⌥Z | Soft wrap | ⌘= ⌘- ⌘0 | Zoom |

The scratch files have timestamps for names, so quick open shows the first line of each file as its title. That's what makes 3,000 files findable.
The character count follows LinkedIn as far as anyone knows. LinkedIn publishes no rule. Buffer's developer guide says it counts UTF-16 units, so an emoji counts 2, and Textee does the same: it never counts too low. Buffer also says a link counts as 24 units whatever its length. Textee doesn't apply that yet.
Textee vs 4 Mac text editors
I measured Textee against the other text editors on my Mac on 13th October: TextMate, CotEditor, Sublime Text and TextEdit. Every app was measured from outside, the same way: launch it or open a file in it, then watch the process until its CPU time stops growing. 7 rounds, medians of the last 6. Every app ran with my own settings, no session restore and a 1920 × 1080 window. My own TextMate kept running: the benchmark used a copy of it with its own bundle id.
How to read it:
- Textee wins 12 of the 16 measures. On average it's 1.1x the best value on each row. TextEdit comes next at 1.7x, then Sublime Text (3.5x), TextMate (3.7x) and CotEditor (5.8x).
- TextEdit is the lightest on memory: 27 MB with 1 small file, 29 MB with the Markdown file. But it shows Markdown as plain text, and it opens each file in its own window. With 11 windows open it used 521 ms of CPU in 15 s of doing nothing, against 12 ms for Textee.
- TextMate wins 1 row: 162 MB with the 22 MB file, against 174 MB for Textee.
- Sublime Text is fast on big files, but it needs 208 MB for 1 small file. That figure includes its plugin processes.
- CotEditor is the slowest here: 3.7 s to open 9 files, 249 MB with 11 files, and 7 s of CPU to colour the Markdown file.
- Not compared: typing. Sending key presses to the other editors needs a permission the benchmark didn't have. Textee's own QA measures 2.6 ms per keystroke, including a full redraw of the editor.
The first run of this comparison wasn't fair, and I threw it away. Amethyst, my window manager, had left each editor's window at a different size: 673 × 439 for TextEdit, 2160 × 3809 for CotEditor. Memory grows with the window. Textee used 124 MB for the Markdown file in the tall window, and 45 MB in a 1200 × 900 one. The second run sets every window to the same size before each launch.
The benchmark also caught a bug. A first comparison with TextMate alone had Textee slower at opening 9 files (1.3 s against 0.8 s): Textee asked macOS to bring itself to the front once per file. One fix later, it was 2.4x faster.
For business people
Textee is a tool for 1 user and 1 habit. It does the scratchpad job I do 8 times a day, and the plain text editing around it, and nothing else.
The value isn't the editor. It's that 2 workarounds disappeared (the word count command and the Hammerspoon overlay), the clipboard flow got faster, and the next change is 1 prompt away.
The trade-off is the same as for every app I build: I maintain it, and nobody else supports it. The code is public, so anyone can build it and make it theirs, but I don't offer support.
For technical people
Stack
| Layer | Choice | Why |
|---|---|---|
| Language and UI | Swift 6 and AppKit, no third-party code | Native, compiled, nothing to load at launch |
| Text engine | NSTextView on TextKit 1 |
Fast on large files, with non-contiguous layout |
| Line numbers | Own gutter view, visible lines only | Draws from an index of line starts, never a full scan |
| Line index | Line-start offsets, updated per edit | Keystroke cost doesn't grow with the file |
| Colours | Own line lexers, temporary attributes | No text-storage edits, so no undo entries, no flicker |
| Counts | Words and UTF-16 units; over 1 MB, background | Typing stays fast in the 22 MB file |
| Saving | Atomic replace, conflict check | Keeps CRLF and BOMs; never writes an empty file over content |
| Build | XcodeGen, Developer ID signing | The project is a text file Claude can edit |
About 4,500 lines of Swift, a QA script with 239 checks and a benchmark script. The QA works on copies of my files in a temp folder, with a private clipboard, so it never touches ~/txt or what I copied.
How the benchmark works
A small Swift probe watches the other app from outside, with no special permission: proc_pid_rusage gives CPU time and memory, the window list gives the moment the window appears. "Work done" is the moment the app's CPU time stops growing for 300 ms. The same probe measures every app, so the comparison is fair even when the absolute numbers are noisy.
Gotchas I hit
- Views don't clip by default since macOS 14. The editor painted over the tab bar until every bar and the editor set
clipsToBounds. - Undo merged several commands into 1 step. NSTextView merges an edit with the previous one unless
breakUndoCoalescing()comes beforeshouldChangeText, not after. - QA steps aren't events. AppKit closes an undo group when it finishes an event, so the QA posts an event after each step, as a real key press would.
- Default apps need a click now. On macOS 26,
dutireports success but nothing changes until I approve a system prompt. - 1 activation per file is slow. macOS already brings an app to the front when it opens a file. Asking again for each file cost up to 2 s.
- ⌥ + a letter never reaches the menu. AppKit types a character instead: ⌥D typed ∂ while the menu showed ⌥D for Delete Line. The text view now finds the ⌥ menu item and runs it. The QA missed it, because it called the menu directly, so it now sends real key presses too.
- Square corners need a window class of its own. AppKit asks each window for its corner mask, but uses the answer only when the window's own class overrides the method. Changing every window at once does nothing.
How I got there: 4 prompts
I built Textee in 1 evening with Claude Code.
| Prompt | What I asked | What happened |
|---|---|---|
| 1 | "Analyse my usage of TextMate, plan the app, ask me all your questions" | It found the ca habit in my Alfred setup and asked 15 questions |
| 2 | My 15 answers, "blue colour scheme", "working app, QA'ed" | Built, tested, installed, default app for .txt, Alfred updated |
| 3 | "Compare it with TextMate", then this note | A first benchmark, and the bug it found |
| 4 | "Add CotEditor, Sublime Text and TextEdit, in a NicAI chart" | The heat map, and a fairer benchmark with equal window sizes |
What worked:
- Usage data before features. The analysis showed I didn't need a project editor. I needed a fast clipboard pad with search.
- Short answers to good questions. "No code sharing with Notee", "Blackboard", "count what LinkedIn counts": each answer cut a branch of work.
- Measure against the thing it replaces. The comparison found a real bug that my own QA, which only measured Textee, had missed.
Further reading
- Notee: my own Markdown editor for macOS: my Markdown editor, built the same way
- The era of personal software is here: why I build my own apps now
- TextMate: my older note on TextMate



