Volver a sangrar automáticamente el código elisp al agregar o quitar código antes de un bloque sangrado

18

Digamos que tengo un código elisp como:

(+ 2 3▮(+ 3
          4))

¿Hay alguna forma de volver a sangrar automáticamente el sexp después del cursor cuando agrego o elimino símbolos?

Entonces, después de presionar SPC 4 SPC, automáticamente obtendría:

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

Puedo hacer este manual llamando mark-sexpseguido de indent-region. ¿Hay mejores formas de hacer esto?

Maciej Goszczycki
fuente
No creo que haya combinaciones de teclas predeterminadas convenientes, pero podría crearlas fácilmente.
shosti
Lo sé, pero me pregunto específicamente si hay mejores formas de hacerlo. Por ejemplo, ¿cómo electric-indent-modees mucho mejor que mapear <return>anewline-and-indent
Maciej Goszczycki

Respuestas:

14

En lugar de mark-sexp+ indent-region, puede presionar C-M-q. Esto llamará indent-pp-sexp. No es automático, pero es un poco mejor que tener que invocar dos comandos.

O si está usando paredit-mode, presione M-q. Eso reindentará toda la definición de función en la que se encuentra.

Dmitry
fuente
1
(add-hook 'post-self-insert-hook 'indent-pp-sexp)Funciona sorprendentemente bien.
Maciej Goszczycki
Se ve bien. Eso puede ser costoso en algunos modos, pero es un buen enfoque, sin embargo.
Dmitry
Para los usuarios de Smartparens, puede reindentificar el defun actual con M-x sp-indent-defun. Ato esto C-M-q.
Radon Rosborough
15

Modo de sangría agresivo

Como algunas personas lo pidieron, convertí esta respuesta en un paquete .

Si tiene Melpa configurado, puede instalarlo con

M-x package-install RET aggressive-indent

Consulte el archivo Léame para ver todas las opciones, pero la forma más sencilla de activarlo es:

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

La vieja respuesta

Lo siguiente hace una sangría automática solo en los buffers de elisp. Tiene la ventaja de funcionar también cuando borra o tira cosas (en lugar de simplemente escribir). También es fácil agregar a otros modos.

Esta función sangrará cualquier expresión-s en la que se encuentre el punto actualmente. Puede vincularlo a una clave si lo desea, pero consulte a continuación primero.

(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))))))

Este enlace hará que esta función se ejecute después de escribir cualquier cosa, pero solo en búferes elisp. Esto debería mantener todo siempre sangrado.

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

¡Intentalo! Funciona notablemente bien.

Además, siguiendo la sugerencia de @ holocronweaver en los comentarios, puede usar algo como lo siguiente para lenguajes tipo c:

(define-key c++-mode-map ";"
  (lambda () (interactive)
    (insert ";")
    (endless/indent-defun)))
Malabarba
fuente
Sería excelente si esto silenciara los mensajes de sangría automática y manejara mejor los idiomas que terminan las líneas con punto y coma.
holocronweaver
@holocronweaver seguro, puedo intentarlo. ¿Qué modo principal tiene mensajes de sangría? ¿Y cuál es el problema con los punto y coma?
Malabarba
Todos los modos que probé en el enlace troncal de Emacs produjeron mensajes de sangría, incluido elisp. Dado que los puntos y comas terminan una línea en muchos idiomas, hasta que escribe el punto y coma, la siguiente línea salta como si fuera parte de la línea actual.
holocronweaver
@holocronweaver Silenció los mensajes. Gracias por mencionarlo.
Malabarba
Gracias por la solución! Una solución al problema de punto y coma es solo sangrar en lenguajes en modo c cuando se escribe un punto y coma.
holocronweaver
3

No conozco una solución preexistente, pero puede usarla post-self-insert-hookpara lograrlo usted mismo:

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

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

Sin embargo, me preocuparía por posibles problemas de rendimiento.

shosti
fuente
1

Puede probar el-fly-indent-mode , que se comporta mejor que aggressive-indent-modecuando se trata de Elisp.

Jiahao
fuente