7.8 KiB
Emacs macOS Build s macOS Zoom Accessibility
Návod na sestavení GNU Emacs pro macOS s patchem, který opravuje sledování kurzoru při zapnutém macOS Zoom ("Follow keyboard focus"). Postup vychází z reálné zkušenosti z buildu v únoru 2026.
Proč je to potřeba
macOS Zoom funguje jako magnifier přes celou obrazovku nebo v okně. Režim "Follow keyboard focus" by měl automaticky posouvat viewport za textovým kurzorem. Ve vanilla GNU Emacs to ale nefunguje.
Příčina: Emacs má vlastní NSView, který neimplementuje NSAccessibility protokol
a hlavně nevolá UAZoomChangeFocus() z HIServices/UniversalAccess.h. Tuto funkci
volají iTerm2 (PTYTextView.m) i Chromium (render_widget_host_view_mac.mm) a
je to jediný spolehlivý způsob, jak Zoom přinutit sledovat kurzor v custom view.
Standardní NSAccessibility notifikace samy o sobě nestačí — Zoom je event-driven
a potřebuje explicitní volání UAZoomChangeFocus() s aktuální pozicí kurzoru
v souřadnicích AX obrazovky (origin vlevo nahoře, tzn. y-osa je otočená oproti
Cocoa, kde origin je vlevo dole).
Patch je uložený v repozitáři martin/emacs-doom na Giteě:
patches/0001-ns-implement-AXBoundsForRange-for-macOS-Zoom-cursor-.patch
Krok 1: Prerekvizity
Nejprve nainstaluj Xcode Command Line Tools (nutné pro kompilaci):
xcode-select --install
Pak nainstaluj závislosti přes Homebrew:
brew install autoconf libgmp texinfo pkg-config gnutls libxml2 jansson tree-sitter librsvg imagemagick
Pro native compilation (volitelné, výrazně rychlejší Emacs):
brew install libgccjit
Krok 2: Stažení zdrojového kódu Emacs
git clone https://github.com/emacs-mirror/emacs.git
cd emacs
git checkout emacs-31
Větev emacs-31 je aktuálně doporučená stable větev. Až bude k dispozici emacs-32,
použij tu.
Krok 3: Aplikace accessibility patche
Stáhni config repozitář s patchem:
git clone https://git.apps.sukany.cz/martin/emacs-doom.git /tmp/emacs-doom-config
Aplikuj patch:
git am /tmp/emacs-doom-config/patches/0001-ns-implement-AXBoundsForRange-for-macOS-Zoom-cursor-.patch
Ověř, že patch byl aplikovaný:
grep "UAZoomChangeFocus" src/nsterm.m | head -3
Výsledkem by mělo být několik řádků s voláním UAZoomChangeFocus. Pokud grep
nic nevrátí, patch se neaplikoval správně.
Co patch přidává do src/nsterm.m:
- Volání
UAZoomChangeFocus()po každém pohybu kurzoru — koordináty jsou přepočítány z Cocoa (origin vlevo dole) do AX prostoru (origin vlevo nahoře) ručním y-flipem:primaryH - y - height NSAccessibilitySelectedTextChangedNotification— notifikace po pohybu kurzoruNSAccessibilityFocusedUIElementChangedNotification— notifikace při zaměření oknaaccessibilityBoundsForRange:— nové API (macOS 10.10+)- Fallback přes starší
AXBoundsForRangepro starší verze NSAccessibilityTextAreaRolepro EmacsView
Krok 4: Konfigurace
Spusť autogen a pak configure. Základní konfigurace (bez native compilation):
./autogen.sh
./configure \
--with-ns \
--with-tree-sitter \
--with-gnutls \
--with-xml2 \
--with-json \
--with-imagemagick \
--with-rsvg \
--with-mailutils \
--without-x \
--without-dbus \
CFLAGS="-O2 -g3"
S native compilation (pokud máš libgccjit):
./configure \
--with-ns \
--with-native-compilation=aot \
--with-tree-sitter \
--with-gnutls \
--with-xml2 \
--with-json \
--without-x \
CFLAGS="-O2 -g3"
Krok 5: Build
make -j$(sysctl -n hw.ncpu)
Parametr -j$(sysctl -n hw.ncpu) použije všechna dostupná jádra. Build trvá
přibližně 5–15 minut podle hardwaru.
Po dokončení build vytvoří nextstep/Emacs.app:
make install
Krok 6: Instalace
Přesuň Emacs.app do /Applications:
cp -r nextstep/Emacs.app /Applications/Emacs.app
Vytvoř wrapper script. Pozor: použij wrapper script, ne symlink. Symlink nefunguje
správně — Emacs počítá cesty k Lisp souborům z argv[0], a přes resolved symlink
je najde špatně. Projeví se to chybami jako:
Warning: arch-dependent data dir 'Contents/MacOS/libexec/': No such file or directory Warning: Lisp directory 'Contents/Resources/lisp': No such file or directory
Správné řešení — wrapper script:
sudo tee /usr/local/bin/emacs > /dev/null << 'EOF'
#!/bin/sh
exec /Applications/Emacs.app/Contents/MacOS/Emacs "$@"
EOF
sudo chmod +x /usr/local/bin/emacs
Ověření:
which emacs
emacs --version
Výstup which emacs musí být /usr/local/bin/emacs.
Krok 7: Accessibility permission
Po každém novém buildu (nový binární soubor) je potřeba znovu udělit oprávnění.
Bez toho UAZoomChangeFocus() neovlivní Zoom viewport — volání proběhne, ale
macOS ho ignoruje bez Accessibility přístupu.
Postup:
- Otevři System Settings → Privacy & Security → Accessibility
- Přidej
/Applications/Emacs.app - Zapni toggle vedle Emacs
Pokud Emacs v seznamu už je (ze starého buildu), odeber ho a přidej znovu — macOS identifikuje aplikace i podle binary hash a starý záznam neplatí.
Krok 8: Doom Emacs sync
Pokud používáš Doom Emacs, spusť sync po instalaci nového Emacsu:
~/.emacs.d/bin/doom sync
Pokud doom hlásí, že nenajde Emacs, zkontroluj:
which emacs
Musí vrátit /usr/local/bin/emacs. Pokud vrátí jinou cestu, je problém
s PATH nebo chybí wrapper script.
Krok 9: Ověření Zoom funkcionality
Nastav Zoom v System Settings:
- System Settings → Accessibility → Zoom
- Zapni "Use keyboard shortcut to zoom" nebo "Use scroll gesture with modifier keys to zoom"
- Zoom style: Full Screen nebo Window (obojí funguje)
- Klikni na "Advanced…" → záložka "Zoom Follows the Cursor"
- Nastav "Zoom follows: Keyboard focus"
Otevři Emacs a začni psát. Zoom viewport by měl automaticky sledovat textový kurzor při každém pohybu (šipky, PageUp/Down, přechod mezi buffery).
Řešení problémů
Zoom nesleduje kurzor
Nejčastější příčiny jsou dvě. Za prvé, chybí Accessibility permission — viz Krok 7. Za druhé, patch nebyl správně aplikovaný. Ověření:
grep "UAZoomChangeFocus" /Applications/Emacs.app/Contents/MacOS/../../../src/nsterm.m 2>/dev/null || \
echo "Zkontroluj zdrojový kód nebo přelož znovu"
Nebo v build adresáři:
grep "UAZoomChangeFocus" src/nsterm.m | wc -l
Pokud výsledek je 0, patch chybí. Aplikuj znovu a přelož.
Build selže na nsterm.m
Zkontroluj, zda jsou nainstalované Xcode Command Line Tools:
xcode-select -p
Pokud cesta neexistuje nebo vrátí chybu, spusť xcode-select --install znovu.
doom sync hlásí "emacs not found"
Zkontroluj wrapper script:
cat /usr/local/bin/emacs
Soubor musí existovat a obsahovat exec /Applications/Emacs.app/Contents/MacOS/Emacs "$@".
Pokud neexistuje, viz Krok 6.
Chyby "libexec not found" nebo "lisp not found" při startu
Příčina je symlink místo wrapper scriptu. Zkontroluj:
ls -la /usr/local/bin/emacs
Pokud výstup ukazuje -> (symlink), smaž ho a vytvoř wrapper script podle Kroku 6.
Reference
- Patch repozitář: martin/emacs-doom
- Podobný problém v Ghostty: https://github.com/nicowillis/Ghostty/issues/4053
- Stejný přístup v iTerm2:
src/PTYTextView.m, funkcerefreshAccessibility - Stejný přístup v Chromium:
render_widget_host_view_mac.mm, funkceOnSelectionBoundsChanged