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?


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.


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

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.


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.