Menguasai Emacs Lisp tingkat lanjut: advice untuk membungkus perilaku fungsi tanpa mengubah sumbernya, hook untuk merespons event, keymap inheritance untuk memodularkan konfigurasi, serta keyboard macros dengan F3/F4 untuk mengotomasi kerja berulang menjadi alat yang reusable.

Di episode 25 kalian merancang keybinding sendiri. Episode 26 membawa kustomisasi ke level berikutnya: menulis Elisp yang mengubah perilaku Emacs secara struktural. Tiga alat utama — advice, hooks, dan keymap inheritance — adalah cara paket-paket besar bekerja tanpa menyentuh sumber Emacs. Ditambah keyboard macros (F3/F4), kalian punya jalan pintas mengotomasi kerja berulang yang sebelumnya butuh menulis fungsi.
Mengapa penting? Karena kemampuan "membungkus" dan "menyambungkan" perilaku inilah yang membedakan pengguna Emacs biasa dari config engineer. Kalian tidak perlu memahami seluruh 40 tahun kode Emacs — cukup tahu di titik mana menyambungkan kode kalian.
Advice mengubah perilaku fungsi tanpa mengedit definisi aslinya. Sejak Emacs 24.4, API modernnya adalah advice-add (paket nadvice):
(defun my/save-log-time (&rest _args)
(message "Disimpan pukul %s" (format-time-string "%H:%M:%S")))
(advice-add 'save-buffer :before #'my/save-log-time)Jenis kombinasi:
(advice-add 'some-fn :around #'my/wrap) ; bungkus: kendalikan sebelum & sesudah
(advice-add 'some-fn :before #'my/before) ; jalankan dulu
(advice-add 'some-fn :after #'my/after) ; jalankan setelah
(advice-add 'some-fn :override #'my/own) ; ganti total (hati-hati!):around adalah yang paling kuat — kalian menerima fungsi asli dan memutuskan kapan memanggilnya:
(defun my/quiet-eshell (_fun &rest args)
"Menjalankan command tapi menyembunyikan noise."
(let ((inhibit-message t))
(apply _fun args)))
(advice-add 'eshell/echo :around #'my/quiet-eshell)Hapus dengan advice-remove atau M-x remove-function.
Hook adalah daftar fungsi yang dijalankan saat event terjadi. Event paling umum adalah mode aktif:
(add-hook 'prog-mode-hook #'display-line-numbers-mode)
(add-hook 'python-ts-mode-hook
(lambda () (setq-local indent-tabs-mode nil)))
(add-hook 'before-save-hook #'delete-trailing-whitespace)Beberapa hook penting:
| Hook | Kapan dipanggil |
|---|---|
emacs-startup-hook | Setelah Emacs selesai start |
find-file-hook | Setiap file dibuka |
after-save-hook / before-save-hook | Sebelum/sesudah simpan |
prog-mode-hook | Setiap major mode bahasa pemrograman |
window-configuration-change-hook | Setiap tata letak window berubah |
Gabungkan hook dengan advice = pola paket besar (misal LSP memakai hook prog-mode-hook + advice find-file-hook).
Keymap inheritance memungkinkan satu keymap mewarisi binding dari keymap lain — pola untuk membuat keymap paket yang bersih:
(defvar my/parent-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "p") #'project-find-file)
(define-key map (kbd "g") #'magit-status)
map)
"Binding dasar.")
(defvar my/mode-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map my/parent-map) ; warisi binding parent
(define-key map (kbd "t") #'my/terminal-toggle)
map)
"Keymap mode dengan warisan dari parent.")Sekarang my/mode-map punya p, g (warisan) plus t miliknya sendiri — jika nanti parent berubah, semua turunan ikut berubah. Ini memungkinkan konfigurasi modular: base keymap untuk semua mode, dan keymap khusus per mode.
Keyboard macro merekam keystrokes dan memutarnya ulang. Sebelum menulis Elisp, makro adalah alat instan:
F3 → mulai merekam
(ketik langkah-langkah, misal: C-a, M-w, C-n)
F4 → berhenti merekam & jalankan sekali
F4 F4 → jalankan ulang terus (sampai error)
C-x C-k k → simpan makro dengan nama
C-x C-k l → daftar makro tersimpanContoh nyata: menambahkan ; TODO di baris kosong pada 20 baris teks:
F3
C-f (tulis "TODO")
C-n
F4 ... F4 20xMakro yang sudah bagus bisa diubah menjadi fungsi permanen:
C-x C-k k → beri nama makro, misal "my-macro"
C-x C-k e → edit makro bernama
M-x insert-kbd-macro → sisipkan definisi ke bufferHasilnya berupa definisi kmacro yang bisa kalian simpan di init:
(fset 'my-insert-todo
[?\C-f ?T ?O ?D ?O ?\C-n])F3/F4 terasa kecil, tapi untuk pekerjaan repetitif (renaming berulang, transformasi blok, format ulang) ia mengalahkan banyak tool eksternal. Untuk kasus yang butuh kondisi atau logika, upgrade dari makro ke fungsi Elisp (episode 9).
Tip
Aturan pemilihan alat otomasi: makro untuk langkah berulang yang deterministik dan pendek; fungsi Elisp untuk yang butuh logika/kondisi; advice/hook untuk menyambungkan ke event Emacs; keybinding (episode 25) sebagai pintu gerbang ke semuanya.
use-package + :config: definisikan advice/hook di dalam blok :config paket, bukan di luar — semua kode terkait hidup dalam satu blok.my/ untuk membedakan kode sendiri dari built-in — mencegah tabrakan nama di masa depan.(unless (advice-member-p ...)) atau add-hook (yang sudah idempoten) agar memuat ulang init file tidak menduplikasi advice.(unless (advice-member-p #'my/save-log-time 'save-buffer)
(advice-add 'save-buffer :before #'my/save-log-time))find-file) sulit di-debug. Periksa dengan M-x describe-function → bagian Advice menampilkan semuanya.add-hook bersifat idempoten (tidak menambah dua kali), tapi lambda anonim yang di-add-hook menghasilkan entri baru setiap evaluasi — pakai named function.setq-local vs setq: di hook mode, setq mengubah nilai global dan bocor ke buffer lain — selalu pakai setq-local untuk pengaturan per-buffer.apply-macro-to-region-lines (C-x C-k r).:override advice tanpa dokumentasi = bom waktu. Beri nama jelas dan tambahkan komentar.Pada episode 26 ini, kalian telah naik level dari pengguna menjadi config engineer Emacs.
Inti yang harus dibawa pulang:
:before, :after, :around, :override) tanpa mengedit sumbernya.set-keymap-parent) membuat konfigurasi modular.F3/F4) mengotomasi langkah berulang instan, dan bisa dikonversi menjadi Elisp permanen.my/, named function, dan idempotensi agar konfigurasi tetap bersih.Di episode 27 selanjutnya, kita berburu milidetik: performa & tuning — native compilation, tuning garbage collector, benchmark-init untuk mengukur startup, dan strategi lazy loading supaya Emacs menyala di bawah 1 detik. Sampai jumpa di episode 27!