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.