Secara otomatis memasukkan kembali kode elisp saat menambahkan atau menghapus kode sebelum blok yang indentasi

18

Katakanlah saya punya kode elisp seperti:

(+ 2 3▮(+ 3
          4))

Apakah ada cara untuk secara otomatis indentasi ulang sexp setelah kursor, ketika saya menambah atau menghapus simbol?

Jadi setelah menekan SPC 4 SPC, saya akan secara otomatis mendapatkan:

(+ 2 3 4 ▮(+ 3
             4))

Saya dapat melakukan manual ini dengan menelepon mark-sexpdiikuti oleh indent-region. Apakah ada cara yang lebih baik untuk melakukan ini?

Maciej Goszczycki
sumber
Saya tidak berpikir ada keybindings default yang mudah digunakan, tetapi Anda dapat dengan mudah membuat beberapa sendiri.
shosti
Saya tahu tetapi saya secara khusus bertanya-tanya apakah ada cara yang lebih baik untuk melakukan ini. Misalnya bagaimana electric-indent-modejauh lebih baik daripada memetakan <return>kenewline-and-indent
Maciej Goszczycki

Jawaban:

14

Alih-alih mark-sexp+ indent-region, Anda dapat menekan C-M-q. Ini akan memanggil indent-pp-sexp. Tidak otomatis, tetapi sedikit lebih baik daripada harus memanggil dua perintah.

Atau jika Anda menggunakan paredit-mode, tekan M-q. Itu akan reindent seluruh definisi fungsi Anda masuk

Dmitry
sumber
1
(add-hook 'post-self-insert-hook 'indent-pp-sexp)bekerja dengan sangat baik.
Maciej Goszczycki
Kelihatan bagus. Itu mungkin mahal dalam beberapa mode, tapi itu pendekatan yang bagus.
Dmitry
Untuk pengguna Smartparens, Anda dapat mengaktifkan kembali defun saat ini M-x sp-indent-defun. Saya mengikat ini C-M-q.
Radon Rosborough
15

Mode Indentasi Agresif

Karena beberapa orang memintanya, saya mengubah jawaban ini menjadi satu paket .

Jika Anda telah mengkonfigurasi Melpa, Anda dapat menginstalnya dengan

M-x package-install RET aggressive-indent

Lihat Readme untuk semua opsi, tetapi cara paling sederhana untuk menyalakannya adalah:

(add-hook 'emacs-lisp-mode-hook #'aggressive-indent-mode)

Jawaban Lama

Berikut ini melakukan indentasi otomatis hanya pada buffer elisp. Ini memiliki keuntungan juga bekerja ketika Anda menghapus atau menarik barang (bukan hanya mengetik). Sangat mudah untuk menambahkan ke mode lain juga.

Fungsi ini akan indentasi apa pun s-ekspresi titik saat ini di dalam Anda dapat mengikatnya ke kunci jika Anda mau, tetapi lihat di bawah terlebih dahulu.

(require 'cl-lib)

(defun endless/indent-defun ()
  "Indent current defun.
Do nothing if mark is active (to avoid deactivating it), or if
buffer is not modified (to avoid creating accidental
modifications)."
  (interactive)
  (ignore-errors
    (unless (or (region-active-p)
                buffer-read-only
                (null (buffer-modified-p)))
      (let ((l (save-excursion (beginning-of-defun 1) (point)))
            (r (save-excursion (end-of-defun 1) (point))))
        (cl-letf (((symbol-function 'message) #'ignore))
          (indent-region l r))))))

Hook ini akan membuatnya sehingga fungsi ini akan berjalan setelah Anda mengetik apa pun, tetapi hanya di buffer elisp. Ini harus menjaga semuanya selalu menjorok ke dalam.

(add-hook
 'emacs-lisp-mode-hook
 (lambda ()
   (add-hook 'post-command-hook
             #'endless/indent-defun nil 'local)))

Cobalah! Ini bekerja dengan sangat baik.

Juga, mengikuti saran @ holocronweaver di komentar, Anda dapat menggunakan sesuatu seperti berikut untuk bahasa c-like:

(define-key c++-mode-map ";"
  (lambda () (interactive)
    (insert ";")
    (endless/indent-defun)))
Malabarba
sumber
Akan sangat baik jika ini membungkam pesan inden otomatis dan bahasa yang ditangani dengan lebih baik yang mengakhiri garis dengan titik koma.
holocronweaver
@holocronweaver yakin, saya bisa mencobanya. Mode utama mana yang memiliki pesan indentasi? Dan apa masalahnya dengan titik koma?
Malabarba
Semua mode yang saya coba pada Emacs trunk menghasilkan pesan indent, termasuk elisp. Karena titik koma mengakhiri sebuah baris dalam banyak bahasa, hingga Anda mengetikkan titik koma, baris berikut melompat seolah-olah itu adalah bagian dari baris saat ini.
holocronweaver
@holocronweaver Membungkam pesan. Terima kasih telah menunjukkannya.
Malabarba
Terima kasih untuk perbaikannya! Salah satu solusi untuk masalah titik koma adalah dengan hanya indentasi dalam bahasa mode-c ketika titik koma diketik.
holocronweaver
3

Saya tidak tahu solusi yang sudah ada sebelumnya, tetapi Anda dapat menggunakannya post-self-insert-hookuntuk menyelesaikannya sendiri:

(defun my-indent-next-sexp ()
  (interactive)
  (mark-sexp)
  (indent-region))

(add-hook 'post-self-insert-hook 'my-indent-next-sexp)

Saya akan khawatir tentang masalah kinerja potensial.

shosti
sumber
1

Anda dapat mencoba mode el-fly-indent , yang berperilaku lebih baik daripada aggressive-indent-modeketika berurusan dengan Elisp.

Jiahao
sumber