A fast terminal text editor that feels native on macOS: the same shortcuts you use in every Mac app, mouse and trackpad support, syntax highlighting and a markdown preview. Written in Rust.
ime notes.md
- Mac keybindings out of the box: ⌥←/→ by word, ⌘←/→ to line start/end, ⌘↑/↓ to start/end of file, Shift to select, ⌘Z / ⇧⌘Z, ⌘S, ⌘A, ⌘C/X/V.
- Works with non-US keyboard layouts: ⌥ keeps typing your characters (
⌥ò→@on an Italian layout); editor commands use ⌥⌘ instead. - Mouse & trackpad: click to place the cursor, drag to select, double-click for a word, triple-click for a line, ⇧-click to extend, smooth vertical and horizontal scrolling.
- Syntax highlighting for ~75 languages (Rust, Go, Python, JS/TS, PHP, C/C++, Markdown, shell, …).
- Auto-closing
( [ { " ' ````, typing over closers, auto-indent on ↩. - Markdown preview (⌥⌘m) right in the terminal.
- Safe saves: written to a temp file and renamed, keeps permissions, CRLF line endings and the trailing newline.
brew install albedev/tap/imeUniversal binary for Apple Silicon and Intel Macs. To update: brew upgrade ime.
From source (needs a Rust toolchain from rustup):
cargo install --git https://github.com/albedev/imeime path/to/file # opens it, or creates it on first saveThe status bar shows the file name, a ● when there are unsaved changes, the cursor position, the detected language, and the shortcuts that work in your current terminal.
ime has two sets of shortcuts:
- ⌘ shortcuts, used when the terminal supports the kitty keyboard protocol and is set up as described below.
- ⌃ fallbacks, which work in every terminal, including Terminal.app.
The status bar tells you which set is active.
Add ⇧ (Shift) to any of these to select while moving.
| Action | Shortcut | Fallback |
|---|---|---|
| Character / line | ← → ↑ ↓ | |
| Word left / right | ⌥← / ⌥→ | |
| Line start / end | ⌘← / ⌘→ | ⌃A / ⌃E, Home / End |
| File start / end | ⌘↑ / ⌘↓ | ⌃Home / ⌃End |
| Page up / down | PgUp / PgDn (fn↑ / fn↓) | |
| Select all | ⌘A | — |
| Clear selection | Esc |
| Action | Shortcut | Fallback |
|---|---|---|
| Delete word left / right | ⌥⌫ / ⌥⌦ | |
| Delete to line start | ⌘⌫ | ⌃U |
| Delete to line end | ⌃K | |
New line (keeps indentation, opens {} blocks) |
↩ | |
| Indent (4 spaces) | ⇥ | |
| Undo / redo | ⌘Z / ⇧⌘Z | ⌃Z / ⌃Y |
| Copy / cut | ⌘C / ⌘X | ⌃C / ⌃X |
| Paste | ⌘V | your terminal's paste |
| Save | ⌘S | ⌃S |
| Quit (press twice to discard unsaved changes) | ⌃Q | ⌃Q |
| Action | Shortcut | Fallback |
|---|---|---|
| Show / hide line numbers | ⌥⌘n | ⌃N |
Markdown preview on / off (.md files) |
⌥⌘m | ⌃P |
| Action | Gesture |
|---|---|
| Place cursor | click |
| Select | drag |
| Select word / line | double-click / triple-click |
| Extend selection | ⇧-click |
| Scroll | two-finger swipe (vertical and horizontal) |
A terminal only passes key presses to the program running inside it as text. Two macOS keys need special handling:
- ⌘ (Command). Terminals normally keep ⌘ for themselves. Terminals that implement the kitty keyboard protocol can pass ⌘ to ime, and ime turns the protocol on automatically. But most terminals also use some ⌘ shortcuts for their own menus (⌘A = select the whole screen, for example). Those need to be freed or remapped.
- ⌥ (Option). On non-US layouts ⌥ types characters you need (
@ # [ ] { } ~). Don't enable "Option as Meta" or "Option as Alt". ime doesn't need it, because arrow keys with ⌥ work either way. Some ⌥ letters are dead keys (on the Italian layout ⌥n starts composingñ), so a few ⌥⌘ shortcuts may need an explicit mapping (below).
| Terminal | ⌘ shortcuts | Setup | Tested |
|---|---|---|---|
| cmux | ✅ | 3 small changes | ✅ yes |
| Ghostty | ✅ | 4 config lines | |
| Terminal.app | ❌ never (no kitty protocol) | none, use the ⌃ fallbacks | |
| iTerm2 | ✅ via key mappings | key mappings | |
| kitty | ✅ | 2 config lines | |
| WezTerm | ✅ | 2 config lines | |
| Alacritty | ✅ via key bindings | key bindings | |
| VS Code, JetBrains, tmux, SSH | ❌ | none, use the ⌃ fallbacks |
"Not yet" means the settings below follow each terminal's documentation but haven't been tried on a real machine. Reports and fixes are welcome.
If your terminal swallows a ⌘ shortcut, map it in the terminal's settings to send this escape sequence. ime understands these sequences in every terminal, even ones without the kitty protocol:
| Shortcut | Escape sequence | As text |
|---|---|---|
| ⌘A | ESC [97;9u |
\e[97;9u |
| ⌘C | ESC [99;9u |
\e[99;9u |
| ⌘X | ESC [120;9u |
\e[120;9u |
| ⌘S | ESC [115;9u |
\e[115;9u |
| ⌘Z | ESC [122;9u |
\e[122;9u |
| ⇧⌘Z | ESC [122;10u |
\e[122;10u |
| ⌥⌘n | ESC [110;11u |
\e[110;11u |
| ⌥⌘m | ESC [109;11u |
\e[109;11u |
The format is ESC [ <key code> ; <modifiers> u. The key code is the character's Unicode value (a = 97). The modifiers value is 1 + Shift 1 + ⌥ 2 + ⌃ 4 + ⌘ 8.
The catch: a remapped key sends this sequence to every program, so in a plain shell the shortcut may print junk like [97;9u.
cmux is built on Ghostty's engine (it reports itself as TERM_PROGRAM=ghostty), but it has its own shortcuts and config files.
1. Send ⌘A, ⌥⌘n and ⌥⌘m to ime. Append to ~/Library/Application Support/com.cmuxterm.app/config.ghostty:
# ime: send these keys straight to the program (skips menus and dead keys)
keybind = super+a=csi:97;9u
keybind = super+alt+n=csi:110;11u
keybind = super+alt+m=csi:109;11u
# ⌘C copies the terminal selection if there is one, otherwise goes to ime
keybind = performable:super+c=copy_to_clipboard2. Free ⌥⌘n. cmux uses it for "New Browser Workspace". In ~/.config/cmux/cmux.json, add right after "schemaVersion": 1,:
3. Free ⌘A from the "Select All" menu item. Menu shortcuts win over keybinds, so move it to an unused combo (⌃⌥⇧⌘A):
defaults write com.cmuxterm.app NSUserKeyEquivalents -dict-add "Select All" '@~^$a'Reload with ⌘⇧, after steps 1–2. Step 3 needs cmux to be quit and reopened.
Trade-offs
- ⌥⌘n no longer opens a browser workspace.
- In a plain shell, ⌘A, ⌥⌘n and ⌥⌘m print junk.
- ⌘A no longer selects the whole terminal (use ⌃⌥⇧⌘A).
- ⌘A may also stop selecting all in cmux's own text fields (address bar, search…).
Undo
defaults delete com.cmuxterm.app NSUserKeyEquivalents
# then remove the lines/blocks added in steps 1 and 2Add to ~/.config/ghostty/config (or ~/Library/Application Support/com.mitchellh.ghostty/config.ghostty):
# ime: send these keys straight to the program (skips menus and dead keys)
keybind = super+a=csi:97;9u
keybind = super+alt+n=csi:110;11u
keybind = super+alt+m=csi:109;11u
# ⌘C copies the terminal selection if there is one, otherwise goes to ime
keybind = performable:super+c=copy_to_clipboardReload with ⌘⇧,. Leave macos-option-as-alt unset: Ghostty already picks the right default for your layout.
Trade-off: in a plain shell ⌘A no longer selects the screen, and ⌘A / ⌥⌘n / ⌥⌘m print junk.
Terminal.app doesn't support the kitty keyboard protocol, so ⌘ shortcuts can never reach ime. Use the ⌃ fallbacks instead; the status bar lists them. Everything else (⌥ word movement, Shift selection, mouse, trackpad, ⌘V paste) works.
Settings → Profiles → your profile:
- Keyboard tab:
- Leave "Use Option as Meta key" off on non-US layouts. ⌥←/→ still move by word, because Terminal sends
ESC b/ESC ffor them by default. - Line start/end: use ⌃A / ⌃E.
- Leave "Use Option as Meta key" off on non-US layouts. ⌥←/→ still move by word, because Terminal sends
- View menu:
- Make sure Allow Mouse Reporting is checked (⌘R toggles it). Without it, clicks and scrolling go to Terminal instead of ime.
Missing here: select all (⌘A). Select with the mouse or with ⇧ + movement keys instead.
Settings → Profiles → your profile → Keys:
-
General: set Left/Right Option key to Normal on non-US layouts.
-
Key Mappings → Presets… → Natural Text Editing. This gives you ⌥←/→, ⌘←/→ and ⌘⌫ as line movement and deletion.
-
Add one mapping per ⌘ shortcut you want: + → press the shortcut → Action Send Escape Sequence → value from the table above without the leading
ESC:Shortcut Send Escape Sequence ⌘A [97;9u⌘S [115;9u⌘Z [122;9u⇧⌘Z [122;10u⌥⌘n [110;11u⌥⌘m [109;11uLeave ⌘C / ⌘V alone so normal copy & paste keeps working; use ⌃C / ⌃X to copy from ime.
Mouse: Profiles → Terminal → Enable mouse reporting (on by default).
kitty is where the keyboard protocol comes from, so ⌘ reaches ime out of the box. In ~/.config/kitty/kitty.conf:
# keep ⌥ typing characters on non-US layouts (this is the default)
macos_option_as_alt no
# ⌘C: copy kitty's selection if there is one, otherwise pass the key to ime
map cmd+c copy_or_noopIn ~/.wezterm.lua:
local wezterm = require 'wezterm'
local config = wezterm.config_builder()
config.enable_kitty_keyboard = true -- lets ⌘ reach ime
config.send_composed_key_when_left_alt_is_pressed = true -- ⌥ò = @ on non-US layouts
return configWezTerm keeps ⌘C / ⌘V for itself; use ⌃C / ⌃X to copy from ime.
In ~/.config/alacritty/alacritty.toml:
[window]
option_as_alt = "None" # keep ⌥ typing characters on non-US layouts
[keyboard]
bindings = [
{ key = "A", mods = "Command", chars = "\u001b[97;9u" },
{ key = "S", mods = "Command", chars = "\u001b[115;9u" },
{ key = "Z", mods = "Command", chars = "\u001b[122;9u" },
{ key = "Z", mods = "Command|Shift", chars = "\u001b[122;10u" },
{ key = "N", mods = "Command|Option", chars = "\u001b[110;11u" },
{ key = "M", mods = "Command|Option", chars = "\u001b[109;11u" },
]VS Code / JetBrains integrated terminals, tmux, SSH sessions: use the ⌃ fallbacks. Mouse and trackpad work as long as the terminal has mouse reporting on.
- tmux: ⌘ shortcuts usually don't make it through tmux. Add
set -g mouse onfor mouse support. - SSH: copy/cut use macOS
pbcopy, so they only work when ime runs on your Mac, not on the remote machine.
See exactly what ime receives
IME_KEYS=1 ime file.txtThe status bar then shows every key and mouse event as ime sees it. For ⌥⌘n you should see something like Char('n') … ALT | SUPER.
Common problems
| Problem | Fix |
|---|---|
| A shortcut does nothing and nothing shows up | The terminal (or one of its menus) took it: free it or map it as described above. |
| A ⌥⌘ shortcut only works with ⇧ | ⌥ + that letter is a dead key on your layout: map it to its escape sequence. |
| The status bar shows ⌃ shortcuts in a terminal that should support ⌘ | The terminal didn't answer the kitty protocol query (check it's enabled, e.g. WezTerm's enable_kitty_keyboard). |
| Clicking or scrolling doesn't work | Turn on mouse reporting in the terminal. |
ime: …: stream did not contain valid UTF-8 |
ime only opens UTF-8 text files. |
- Wide characters (CJK, emoji) count as one column, so the cursor drifts on those lines.
- The syntax colors use a fixed dark theme and look washed out on light terminal backgrounds.
- After a jump into a very large file, highlighting restarts 300 lines above the view. A comment or string longer than that can be colored wrong.
- Not there yet: find/replace, multiple files, soft wrap.
cargo test # unit tests
cargo run -- samples/test.mdsamples/ has a .txt, .md and .php file for trying the editor and its highlighting.
MIT © 2026 Alberindo Loffrè