¿Hay un paquete o modo de alineación automática para Emacs?

15

Hay momentos en que estoy editando archivos (manifiestos de Puppet, por ejemplo) donde quiero alinear los contenidos del búfer sobre la marcha. Por ejemplo, sé que puedo usar align-regexpo alignalinear código como este, siempre que lo tenga seleccionado:

# M-x align-regexp "=>" will line everything up nicely 
file { "/etc/foo":
  ensure => present,
  mode => "0666",
  source => "puppet:///modules/example/foo",
}

Pero lo que realmente quiero es que esto suceda sobre la marcha , sin tener que seleccionar una región o todo el búfer. ¿Hay un paquete o modo que haga esto, o es algo que debería integrarse en el modo que me interesa?

Editar: pregunté sobre Puppet y CFEngine, ya que eso es lo que codifico en la mayoría de estos días y tengo una gran preferencia por el texto alineado. Sin embargo, también tenía curiosidad (y no expresé esto bien) de saber si la alineación sobre la marcha es una característica común en los modos Emacs (principalmente en los modos para lenguajes de programación), o si la mayoría de las personas se alinean al guardar o en algún momento otro punto

San Aardvark el Alfombrado
fuente
Hay expand-region , que es útil para seleccionar ámbitos sucesivamente más grandes.
bastibe
1
¿Puedes describir más sobre lo que normalmente alinearías? ¿Son solo signos iguales y en modo títere? Puede modificar el código en esta respuesta de Emacs SE para la sangría automática de @Malabarba para obtener lo que desea. Simplemente reemplace indent-regioncon align-to-equalsy defina esta función como (defun align-to-equals (begin end) (interactive "r") (align-regexp begin end "\\(\\s-*\\)=" 1 1 nil)); y emacs-lisp-mode-hookcon puppet-mode-hook.
Kaushal Modi

Respuestas:

5

Si desea marcar una región para la alineación automática, entonces probablemente no sea demasiado difícil hacer algo como:

(require 'cl-lib)

(defvar my--auto-align-overlays nil)
(make-variable-buffer-local 'my--auto-align-overlays)

(defun my-auto-align (beg end regexp)
  (interactive "r\nsRegexp: ")
  (let ((ol (make-overlay beg end)))
    (overlay-put ol 'evaporate t)
    (overlay-put ol 'my--auto-align-regexp regexp)
    (overlay-put ol 'modification-hooks '(my--auto-align-function))
    (push ol my--auto-align-overlays)
    (add-hook 'post-command-hook 'my--auto-align-pch nil t)))

(defun my--auto-align-function (ol &rest _args)
  (cl-pushnew ol my--auto-align-overlays)
  (add-hook 'post-command-hook 'my--auto-align-pch nil t))

(defun my--auto-align-pch ()
  (dolist (ol my--auto-align-overlays)
    (align-regexp (overlay-start ol) (overlay-end ol)
                  (concat "\\(\\s-*\\)" (overlay-get ol 'my--auto-align-regexp))
                  1 align-default-spacing))
  (setq my--auto-align-overlays nil)
  (remove-hook 'post-command-hook 'my--auto-align-pch))

Pero si desea que sea completamente automático, necesitará encontrar una manera de caracterizar qué regiones desea alinear automáticamente (y con qué expresión regular), lo cual es más difícil. Supongo que podría proporcionar algunas expresiones regulares y luego escanear el búfer en busca de líneas consecutivas que coincidan con una de esas expresiones regulares.

Stefan
fuente
No he usado superposiciones antes, pero el manual de Elisp parece decir que son para alterar la apariencia, ¿lo he entendido bien? Si es así, ¿eso significa que esta respuesta solo altera el aspecto del búfer, en lugar del contenido real del archivo una vez que se guarda? (Es lo último que estaba buscando, pero cambiar la apariencia sería una opción interesante.)
San Aardvark el Alfombrado
2
@SaintAardvarktheCarpeted Overlays se usan comúnmente para alterar la apariencia, pero su aplicabilidad va más allá de eso. En esta respuesta (IIUC), las superposiciones se usan para marcar regiones que se deben alinear (por lo que el búfer realmente cambia, no solo la apariencia). La función my-auto-alignse utiliza para definir estas superposiciones (marque las regiones que desea alinear). La razón (creo) que Stefan está pasando por todos estos problemas es que (a diferencia de la sangría) si solo intenta alinear todo el búfer, obtendrá resultados no deseados, por lo que debe alinear las piezas a la vez.
Malabarba
3

Modo títere proporciona puppet-align-block. Puede organizar la invocación automática de esta función, por ejemplo, agregándola post-command-hooklocalmente (sin probar):

(defun puppet-auto-align ()
  (unless (puppet-in-string-or-comment-p)
    (puppet-align-block)))

(define-minor-mode puppet-auto-align-mode
  :init-value nil
  :keymap nil
  :lighter "PAl"
  :group 'puppet-lint
  (if puppet-auto-align-mode
      (add-hook 'post-command-hook #'puppet-auto-align nil 'local)
    (remove-hook 'post-command-hook #'puppet-auto-align 'local)))

(add-hook 'puppet-mode-hook #'puppet-auto-align-mode)

Tenga en cuenta, sin embargo, que hay una buena razón para no hacer esto. No es particularmente inteligente, y sobrescribirá cualquier alineación manual que pueda hacer en cualquier lugar, lo que se romperá particularmente mal, si la alineación automática no funciona para un código Puppet más complicado.

Por lo tanto, hablando como mantenedor del modo Puppet, recomiendo no hacerlo, y no le ayudaremos ni aceptaremos informes de errores, si está utilizando este código.

Además, para bloques de recursos grandes, puede ser lento, por lo que probablemente desee usar un temporizador inactivo en lugar de post-command-hookdirectamente.

Lunaryorn
fuente