Bagaimana cara memodulasi konfigurasi emacs?

Saya telah memutuskan untuk menulis ulang .emacs saya dari awal, dan saya ingin menyiapkan sesuatu yang modular, untuk menghindari file init.el 1k+ LoC yang ditakuti...

Saya rasa ada beberapa permasalahan mendasar yang perlu diatasi oleh setiap konfigurasi:

  • pilihan global
  • fungsi pengeditan
  • navigasi (bingkai & buffer)
  • ikatan kunci
  • penyesuaian mode

Sementara saya masih berusaha memikirkan strukturnya secara menyeluruh, saya mencari beberapa petunjuk tentang cara mencapai hal ini.
Saya telah melihat beberapa .emacs di github dan semacamnya, dan tampaknya ada pendekatan yang berbeda, dan tidak ada cara yang lebih disukai untuk melakukan ini, yang agak membingungkan.
Saya tertarik membaca beberapa ide mengenai cara menyusun pengaturan seperti itu, dan terutama beberapa kode elisp terkait.


sunting : Telah sibuk dengan banyak hal, dan belum punya banyak waktu untuk bermain-main dengan ini. Akan mencoba metode yang diusulkan dalam beberapa hari, dan melihat mana yang terbaik, sementara itu terima kasih atas semua rekomendasinya!


sunting2: Saya telah menggunakan melek file init dengan org-mode, dan ini benar-benar hebat!
Saya belum menyetel mekanisme pemuatan tertentu, saya telah menggunakan kode ini, untuk memuat direktori elisp saya secara rekursif, lalu memerlukan atau apa pun yang tertulis dalam petunjuk penyiapan.

  (if (fboundp 'normal-top-level-add-subdirs-to-load-path)
  (let* ((my-lisp-dir "~/.emacs.d/elisp/")
  (default-directory my-lisp-dir))
  (setq load-path (cons my-lisp-dir load-path))
  (normal-top-level-add-subdirs-to-load-path)))

Saya masih perlu memoles ini, mungkin menggunakan autoload, dan beberapa byte-kompilasi ulang jika trik dimodifikasi; akan senang mendengar saran tentang itu.


person julien    schedule 16.01.2010    source sumber


Jawaban (10)


File .emacs saya memuat ~/.emacs.d/init.el, yang mendefinisikan fungsi-fungsi berikut, yang ditulis pertama kali untuk XEmacs, tetapi berfungsi cukup baik untuk Emacs saat ini:

(defconst user-init-dir
  (cond ((boundp 'user-emacs-directory)
         user-emacs-directory)
        ((boundp 'user-init-directory)
         user-init-directory)
        (t "~/.emacs.d/")))


(defun load-user-file (file)
  (interactive "f")
  "Load a file in current user's configuration directory"
  (load-file (expand-file-name file user-init-dir)))

Kemudian sisa filenya masuk dan memuat banyak file individual dengan bentuk seperti ini:

(load-user-file "personal.el")

Kumpulan file saya saat ini adalah sebagai berikut:

  • pribadi.el
  • platform.el
  • cygwin.el
  • variabel.el
  • jalur.el
  • surat-berita.el
  • misc-funcs.el
  • bbdb.el
  • kalender.el
  • gnus-funcs.el
  • c-dan-java.el
  • cadel.el
  • clojure.el
  • go.el
  • penurunan harga.el
  • sgml-xml.el
  • teks.el
  • ejaan.el
  • org.el
  • paket.el
  • font.el
  • warna-tema.el
  • bingkai.el
  • server.el
  • kunci.el
  • aquamacs.el

Beberapa di antaranya memiliki tujuan yang jauh lebih spesifik dibandingkan yang lain, sesuai dengan namanya. Semakin detail filenya, semakin mudah untuk menonaktifkan sekelompok formulir saat Anda menginstal ulang paket atau pustaka. Hal ini sangat berguna ketika "pindah" ke sistem baru, di mana Anda menyeret file konfigurasi Anda tetapi belum menginstal semua paket pendukung.

person seh    schedule 16.01.2010
comment
Apa yang saya tuju. Bagus. - person dmckee --- ex-moderator kitten; 17.01.2010
comment
Itu sebabnya saya cenderung menyimpan paket pendukung di suatu tempat di folder .emacs saya. - person klynch; 19.08.2010
comment
Bukankah nama file akan bertentangan dengan paket sebenarnya? Atau Anda memuat path lengkap, bukan persyaratan sederhana? - person xwl; 11.06.2014
comment
Perhatikan panggilan ke load-file yang ditunjukkan di atas: ini menyediakan jalur yang dibentuk dari nama basis file dalam user-init-dir. Artinya, daripada mencoba memuat file pertama bernama markdown.el dari load-path, ia akan secara khusus memuat file /home/myusername/.emacs.d/markdown.el. - person seh; 11.06.2014
comment
Malam ini saya menemukan penggunaan org-mode yang cerdik oleh Aaron Bedra untuk mendefinisikan konfigurasinya sebagai program yang kompeten: github.com/abedra/emacs.d. Lihat dokumentasi org-as-HTML yang diekspor di sini: aaronbedra.com/emacs.d. Saya terinspirasi untuk mencoba mengubah pendekatan konfigurasi saya untuk menggunakan satu file seperti ini, meskipun saya kehilangan pelacakan kontrol versi yang lebih tepat ketika saya mengubah hanya beberapa hal terkait di salah satu file yang tercantum di atas. Apakah kemampuan menulis dokumentasi layak membalikkan pengaturan dokumentasi-di dalam-kode yang normal? - person seh; 15.01.2015

Untuk membagi penyesuaian menjadi beberapa file berbeda, Anda dapat menggunakan initsplit.el. Selain itu, wiki juga memiliki halaman tentang tata letak .emacs modular.

person Joe Casadonte    schedule 17.01.2010

Anda dapat melakukan (require 'foo) dan itu akan memuat temuan elisp "foo.el" pertama di jalur pemuatan Anda, atau (require 'foo "/home/user/experimental/foo.el") untuk sesuatu di luar jalur pemuatan Anda. Ini akan melaporkan kesalahan jika "foo.el" tidak mengandung ekspresi (provide 'foo). Dalam situasi buruk Anda dapat melakukan (require 'foo "bar.el"), dan ini akan berfungsi selama "bar.el" memiliki klausa (provide 'foo).

person Justin Smith    schedule 16.01.2010

Apa salahnya menggunakan load-file?

Beberapa bit tambahan yang mungkin berguna bagi Anda termasuk

  • file-exists-p
  • file-expand-wildcards

Gunakan C-h f <function> untuk mendapatkan bantuan, dan Anda mungkin menemukan Pengantar Pemrograman di Emacs Lisp berguna (atau unduh PDF)

person dmckee --- ex-moderator kitten    schedule 16.01.2010

Jika Anda ingin membagi custom-set-variables Anda, tetapi menginginkan sesuatu yang lebih ringan dari initsplit.el, cobalah ini:

(defmacro custom-set-variable (var value)
  "Call `custom-set-variables' with a warning shown
when customizing using the customize GUI.

XXX: does not support setting the optional NOW and
REQUEST (dependency) fields."
  (custom-set-variables
    ;; `load-file-name' is set by `load-file':
    ;; http://stackoverflow.com/a/1971376/470844
    `(,var ,value nil nil
      ,(format "!!! CAREFUL: CUSTOM-SET IN %s !!!" load-file-name))))

Sekarang, letakkan modul konfigurasi Anda di file terpisah, dan muat dengan load-file di ~/.emacs Anda, seperti yang disarankan orang lain. Di setiap modul konfigurasi, gunakan

(custom-set-variable var value)

alih-alih

(custom-set-variables '(var value))

or

(setq-default var value)

saat mengatur variabel yang dikelola dengan menyesuaikan. Kemudian, jika Anda perlu menyesuaikan variabel menggunakan antarmuka penyesuaian, Anda akan melihat peringatan yang memberi tahu Anda di file mana penyesuaian tersebut harus disimpan:

"!!! CAREFUL: CUSTOM-SET IN <path to module file> !!!"

Jika Anda mengontrol versi file konfigurasi Anda, maka diff akan memberi tahu baris mana dari ~/.emacs Anda yang akan dipindahkan ke modul khusus.

Diskusi masalah dengan naif menggunakan beberapa panggilan custom-set-variables: http://www.dotemacs.de/custbuffer.html

Sunting: Respons terhadap pertanyaan Alan

Masalah yang dipecahkan oleh makro custom-set-variable di atas

Antarmuka penyesuaian di Emacs menyimpan semua variabel kumpulan khusus di ~/.emacs Anda setiap kali Anda mengedit variabel kumpulan khusus apa pun. Jika Anda memodulasi variabel set kustom Anda, dengan menyebarkannya ke beberapa file, maka Anda perlu menyadari kapan emacs menyisipkan pengaturan duplikat di .emacs Anda, dan menghapusnya. Makro custom-set-variable di atas membantu Anda melakukan ini.

Contoh nyata dari file konfigurasi saya

Saya mengatur variabel khusus yang terkait dengan spasi dalam file ~/.emacs.d/extensions/whitespace.el yang dimuat oleh ~/.emacs. Misalnya, saya menyetel search-whitespace-regexp seperti ini:

(nc:custom-set-variable search-whitespace-regexp "[ \t\r\n]+")

Sekarang, ada dua hal yang terjadi. Pertama, ketika saya menemukan variabel itu di antarmuka penyesuaian, saya mendapat peringatan:

Peringatan yang dihasilkan dalam dialog penyesuaian Emacs

Kedua, jika saya mengedit variabel apa pun menggunakan antarmuka penyesuaian, ~/.emacs saya membuatnya sangat jelas bahwa saya telah membayangi beberapa definisi. Misalnya, setelah mengubah search-whitespace-regexp dan global-whitespace-mode di antarmuka penyesuaian, saya mendapatkan:

$ svn di --diff-cmd "diff" -x "-U0" ~/v/conf
Index: /home/collins/v/conf/dot.emacs
===================================================================
--- /home/collins/v/conf/dot.emacs  (revision 267)
+++ /home/collins/v/conf/dot.emacs  (working copy)
@@ -55,0 +56 @@
+ '(agda2-include-dirs (\` ("." (\, (file-truename "~/local/opt/agda-std-lib/src")))) nil nil "!!! CAREFUL: CUSTOM-SET IN /home/collins/.emacs.d/extensions/agda.el !!!")
@@ -58,0 +60,3 @@
+ '(global-whitespace-mode t)
+ '(indent-tabs-mode nil nil nil "!!! CAREFUL: CUSTOM-SET IN /home/collins/.emacs.d/extensions/whitespace.el !!!")
+ '(indicate-empty-lines t nil nil "!!! CAREFUL: CUSTOM-SET IN /home/collins/.emacs.d/extensions/whitespace.el !!!")
@@ -72,0 +77 @@
+ '(search-whitespace-regexp "" nil nil "!!! CAREFUL: CUSTOM-SET IN /home/collins/.emacs.d/extensions/whitespace.el !!!")
@@ -74,0 +80 @@
+ '(tab-width 2 nil nil "!!! CAREFUL: CUSTOM-SET IN /home/collins/.emacs.d/extensions/whitespace.el !!!")

Makro tidak membantu saya mengingat bahwa saya mengubah search-whitespace-regexp, hanya saja sudah disetel di tempat lain, tetapi makro membantu saya mengetahui pengaturan variabel mana yang harus saya hapus dari ~/.emacs saya (semua yang memiliki peringatan), dan mana yang harus saya tinggalkan. ~/.emacs saya, atau pindah ke file terpisah lainnya (semuanya tanpa peringatan).

Kesimpulan

Makro mungkin berlebihan, tetapi begitu ada, makro ini mudah digunakan, dan membuatnya lebih mudah untuk menghindari kesalahan dengan variabel set kustom yang dibayangi.

person ntc2    schedule 10.06.2012
comment
Jadi apa gunanya antarmuka penyesuaian setelah Anda memiliki kode ini? Apakah Anda harus menyimpan perubahan melalui antarmuka, lalu mentransfer perubahan yang dihasilkan dalam file .emacs ke file khusus Anda, menghapusnya dari file .emacs Anda? - person Alan; 02.03.2013
comment
Juga, saya kira Anda mengatakan bahwa Anda akan mengubah sesuatu seperti ini: (custom-set-variables '(column-number-mode t) '(display-time-mode t)) menjadi ini: (custom- set-variabel kolom-mode nomor t) (mode tampilan-waktu-variabel-kustom t) Apakah benar? - person Alan; 02.03.2013
comment
@Alan: lihat contoh baru di atas. Kegunaan utamanya adalah untuk membantu Anda menghindari pengaturan variabel dua kali secara tidak sengaja, dalam dua file berbeda, saat menggunakan antarmuka penyesuaian. Anda dapat melakukan perubahan melalui antarmuka atau langsung di file konfigurasi, tetapi dalam praktiknya menurut saya antarmuka lebih ramah, misalnya. ketika saya tidak tahu apa nama variabel yang saya ubah, jadi saya menjelajah dalam penyesuaian. Dan ya, saya menggunakannya seperti yang Anda sarankan. - person ntc2; 03.03.2013
comment
Terima kasih atas penjelasannya yang sangat jelas dan gamblang. Saya mengerti cara kerjanya sekarang. - person Alan; 04.03.2013
comment
Intinya tentang mengubah opsi apa pun melalui UI kustomisasi, menghasilkan semua opsi kustom yang disetel secara terprogram (dengan custom-set-variables) diduplikasi dalam file kustom yang dinominasikan adalah kuncinya - Saya juga menjelaskan maksudnya mungkin terlalu banyak detail di sini, melalui demonstrasi langkah demi langkah tentang perbedaan setq vs custom-set-variables jika itu membantu orang: emacs.stackexchange.com/questions/55018/ - person Phil; 23.02.2020

Lihatlah starter kit emacs yang luar biasa yang ditata dengan sangat baik dan juga mencakup ELPA paket. Saya menggunakan struktur tersebut sebagai inspirasi untuk pengaturan saya yang lebih sederhana.

person justinhj    schedule 17.01.2010

Terima kasih kepada @JoeCasadonte karena telah menyebutkan halaman EmacsWiki. Karena saya menggunakan Debian dan Ubuntu, cuplikan khusus ini berfungsi dengan baik (untuk dimasukkan ke dalam .emacs.d/init.el):

(setq dotfiles-dir (file-name-directory (or load-file-name (buffer-file-name))))

(let ((user-site-start-dir (concat dotfiles-dir "/site-start.d")))
    (debian-run-directories user-site-start-dir))

Lalu, saya hanya perlu memasukkan file .el saya ke dalam ~/.emacs.d/site-start.d (mis. ~/.emacs.d/site-start.d/50cedet.el) dan semuanya dimuat secara otomatis.

person Paulo    schedule 28.12.2014

Berikut adalah perpustakaan yang memungkinkan Anda menginstal modul baru hanya dengan menyimpannya di direktori yang ditentukan. Itu dapat diunduh dan diinstal dari http://github.com/trileee/my-site-start/

    ;;; my-site-start.el --- set up personal .emacs.d/site-start.d/
    ;;
    ;; Copyright (C) era eriksson <http://www.iki.fi/~era/> 2008-2009
    ;; License: GPL v2
    ;; Version: see `my-site-start-version' below
    ;;
    ;;; Commentary:
    ;;
    ;; The purpose of my-site-start is to simplify maintenance of user libraries.
    ;; Instead of indefinitely tweaking your .emacs, just create a site-start.d
    ;; directory and add symlinks to the libraries you want to load into Emacs.

Arsitektur ini menerapkan beberapa konvensi yang mungkin Anda sukai atau tidak. Lihat bagian komentar lainnya di dekat bagian atas file untuk informasi selengkapnya.

Saya penulis kode ini, dan menghargai masukan apa pun (walaupun tidak secara langsung melalui forum publik ini).

person tripleee    schedule 06.08.2011

Apa yang telah saya lakukan adalah untuk setiap hal, X, yang mungkin ingin saya gunakan, membuat file bernama konfigurasi-X, dan memasukkan require yang sesuai di .emacs. Fitur ini kemudian dapat dihapus dengan mengomentari satu baris.

Misalnya, untuk memilih yang paling sederhana (jika namanya paling buruk), saya memiliki konfigurasi-gambar-dan-artis-mode.el. File ini sangat sederhana:

(global-set-key (kbd "C-M-P")
                'picture-mode)

(provide 'configure-picture-and-artist-mode)

Dan di .emacs:

(require 'configure-picture-and-artist-mode)

Setelah menyelesaikan masalah ini, saya tidak memiliki apa pun di .emacs saya kecuali daftar besar requires dan beberapa perubahan pada load-path, paket tertentu dapat dihapus dengan mudah, dan semua konfigurasi untuk setiap paket ada di satu tempat.

(Saya juga punya file .el penampung semua yang saya gunakan untuk menyimpan hal-hal yang tidak memiliki rumah yang jelas (pengikatan kunci global saya, fungsi pembantu, dll.) tetapi idealnya masih ingin menghindari .emacs. Ini bit tidak terlalu modular, dan mungkin menimbulkan ketergantungan implisit pada paket-paket yang seharusnya dapat dibongkar dengan mudah oleh skema saya, tetapi dalam praktiknya hal itu tampaknya bukan masalah besar.)

person Community    schedule 16.01.2010
comment
Bisakah Anda berbagi lebih banyak tentang cara Anda membujuk 'wajib' untuk menemukan file yang berisi formulir 'menyediakan'? Apakah Anda menentukan nama file untuk argumen kedua require? - person seh; 17.01.2010
comment
@seh Anda tidak perlu melakukannya selama file 'disediakan' ada di jalur muat. Saya dapat memiliki file foo.el, di dalamnya saya memiliki (menyediakan 'foo) atau (menyediakan 'foobar) atau apa pun, lalu di file init saya dapat mengatakan (memerlukan 'foo) (atau foobar atau apa pun) dan itu akan memuat file. - person vedang; 17.01.2010
comment
Saya menamai setiap file dengan simbol yang diberikan, memastikan folder yang memuatnya ada di jalur muat... dan itu berhasil. (Saya tidak yakin dengan detail seluk beluk mekanisme ini, tapi saya curiga require hanya tahu untuk mencoba memuat file yang diberi nama simbol jika tidak ada file yang dimuat yang menyediakan simbol yang diminta. Pokoknya ini yang saya lakukan Saya memperhatikan kinerja file elisp lainnya, jadi saya menyalinnya.) - person ; 17.01.2010
comment
Terima kasih. Saya akan bereksperimen dengan pengaturan ini di file konfigurasi saya sendiri hari ini. - person seh; 17.01.2010
comment
Lihat C-h f require RET untuk rincian cara kerja mekanisme tersebut. Perhatikan juga argumen NOERROR, yang memfasilitasi perilaku bersyarat tergantung pada apakah fitur tersebut dapat dimuat atau tidak. - person phils; 03.03.2013

Anda dapat mencoba init-loader.el, yang merupakan pemuat file konfigurasi. init-loader.el memuat file konfigurasi dari direktori yang ditentukan. Ini memungkinkan Anda untuk mengkategorikan konfigurasi Anda dan memisahkannya menjadi beberapa file.

Untuk info lebih lanjut, silakan kunjungi Repo GitHub init-loader

person Juanito Fatas    schedule 05.04.2013