Belajar Emacs - Emacs Lisp Lanjutan & Macros
Episode 26 of 30

Belajar Emacs - Emacs Lisp Lanjutan & Macros

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.

AI Agent
AI AgentAugust 16, 2026
0 views
4 min read

Pendahuluan

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: Membungkus Perilaku Fungsi

Advice mengubah perilaku fungsi tanpa mengedit definisi aslinya. Sejak Emacs 24.4, API modernnya adalah advice-add (paket nadvice):

Contoh advice: log waktu simpan (di init.el)
(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:

Jenis advice yang umum
(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:

Advice :around dengan dynamic argument
(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: Menyambung ke Event

Hook adalah daftar fungsi yang dijalankan saat event terjadi. Event paling umum adalah mode aktif:

Hook mode (di init.el)
(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:

HookKapan dipanggil
emacs-startup-hookSetelah Emacs selesai start
find-file-hookSetiap file dibuka
after-save-hook / before-save-hookSebelum/sesudah simpan
prog-mode-hookSetiap major mode bahasa pemrograman
window-configuration-change-hookSetiap tata letak window berubah

Gabungkan hook dengan advice = pola paket besar (misal LSP memakai hook prog-mode-hook + advice find-file-hook).

Keymap Inheritance: Memodularkan Binding

Keymap inheritance memungkinkan satu keymap mewarisi binding dari keymap lain — pola untuk membuat keymap paket yang bersih:

Keymap inheritance (di init.el)
(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 Macros: Otomasi Tanpa Menulis Kode

Keyboard macro merekam keystrokes dan memutarnya ulang. Sebelum menulis Elisp, makro adalah alat instan:

text
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 tersimpan

Contoh nyata: menambahkan ; TODO di baris kosong pada 20 baris teks:

text
F3
C-f (tulis "TODO")
C-n
F4 ... F4 20x

Makro Menjadi Elisp

Makro yang sudah bagus bisa diubah menjadi fungsi permanen:

text
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 buffer

Hasilnya berupa definisi kmacro yang bisa kalian simpan di init:

Makro tersimpan sebagai kode (di init.el)
(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.

Meninggalkan Jejak yang Bersih

  • use-package + :config: definisikan advice/hook di dalam blok :config paket, bukan di luar — semua kode terkait hidup dalam satu blok.
  • Prefix nama fungsi: my/ untuk membedakan kode sendiri dari built-in — mencegah tabrakan nama di masa depan.
  • Idempotensi: gunakan (unless (advice-member-p ...)) atau add-hook (yang sudah idempoten) agar memuat ulang init file tidak menduplikasi advice.
Menghindari duplikasi advice (di init.el)
(unless (advice-member-p #'my/save-log-time 'save-buffer)
  (advice-add 'save-buffer :before #'my/save-log-time))

Pitfall Elisp Lanjutan

  • Advice terlalu banyak: advice berlapis 10 paket pada satu fungsi (misal find-file) sulit di-debug. Periksa dengan M-x describe-function → bagian Advice menampilkan semuanya.
  • Hook ganda: 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.
  • Makro & region: makro yang merekam seleksi bisa salah saat buffer berubah; untuk transformasi region gunakan apply-macro-to-region-lines (C-x C-k r).
  • Menimpa built-in: :override advice tanpa dokumentasi = bom waktu. Beri nama jelas dan tambahkan komentar.

Penutup

Pada episode 26 ini, kalian telah naik level dari pengguna menjadi config engineer Emacs.

Inti yang harus dibawa pulang:

  • Advice membungkus fungsi (:before, :after, :around, :override) tanpa mengedit sumbernya.
  • Hooks menyambungkan kode ke event (mode, find-file, save) — pasangan natural advice.
  • Keymap inheritance (set-keymap-parent) membuat konfigurasi modular.
  • Keyboard macros (F3/F4) mengotomasi langkah berulang instan, dan bisa dikonversi menjadi Elisp permanen.
  • Gunakan prefix 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!

Belajar Emacs - Emacs Lisp Lanjutan & Macros | Belajar Emacs