Existe-t-il un package ou un mode d'alignement automatique pour Emacs?

15

Il y a des moments où je modifie des fichiers (manifestes de marionnettes, par exemple) où je veux aligner le contenu du tampon à la volée. Par exemple, je sais que je peux utiliser align-regexpou alignpour aligner un code comme celui-ci, tant que je l'ai sélectionné:

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

Mais ce que je veux vraiment, c'est que cela se produise à la volée - sans avoir à sélectionner une région ou la totalité du tampon. Existe-t-il un package ou un mode qui fera cela, ou est-ce quelque chose qui devrait être intégré au mode qui m'intéresse?

Edit: J'ai posé des questions sur Puppet et CFEngine, car c'est ce que je code la plupart du temps et j'ai une forte préférence pour le texte aligné. Cependant, j'étais également curieux (et je ne l'ai pas bien exprimé) de savoir si l'alignement à la volée est une fonctionnalité courante dans les modes Emacs (principalement dans les modes pour les langages de programmation), ou si la plupart des gens s'alignent lors de l'enregistrement ou à certains moments. autre point.

Saint Aardvark le Moquette
la source
Il existe une zone d' extension , qui est utile pour sélectionner des étendues successivement plus grandes.
bastibe
1
Pouvez-vous décrire davantage ce que vous aligneriez habituellement? Est-ce juste des signes égaux et en mode marionnette? Vous pouvez modifier le code dans cette réponse Emacs SE pour l'indentation automatique par @Malabarba pour obtenir ce que vous voulez. Remplacez simplement indent-regionpar align-to-equalset définissez cette fonction comme (defun align-to-equals (begin end) (interactive "r") (align-regexp begin end "\\(\\s-*\\)=" 1 1 nil)); et emacs-lisp-mode-hookavec puppet-mode-hook.
Kaushal Modi

Réponses:

5

Si vous souhaitez marquer une région pour l'alignement automatique, ce n'est probablement pas trop difficile à faire avec quelque chose comme:

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

Mais si vous voulez qu'il soit entièrement automatique, vous devez trouver un moyen de caractériser les régions que vous souhaitez aligner automatiquement (et avec quelle expression rationnelle), ce qui est plus difficile. Je suppose que vous pouvez fournir des expressions régulières, puis analyser le tampon pour trouver des lignes consécutives correspondant à l'une de ces expressions régulières.

Stefan
la source
Je n'ai jamais utilisé de superpositions auparavant, mais le manuel Elisp semble dire qu'elles sont destinées à modifier l'apparence - ai-je bien compris? Si oui, cela signifie-t-il que cette réponse ne modifie que l'apparence du tampon, plutôt que le contenu réel du fichier une fois qu'il est enregistré? (C'est ce dernier que je cherchais, mais changer d'apparence serait une option intéressante.)
Saint Aardvark the Carpeted
2
@SaintAardvarktheCarpeted Overlays sont couramment utilisés pour modifier l'apparence, mais leur applicabilité va au-delà. Dans cette réponse (IIUC), les superpositions sont utilisées pour marquer les régions qui doivent être alignées (donc le tampon est vraiment changé, pas seulement l'apparence). La fonction my-auto-alignest utilisée pour définir ces superpositions (marquez les régions que vous souhaitez aligner). La raison (je pense) que Stefan traverse tous ces problèmes est que (contrairement à l'indentation) si vous essayez simplement d'aligner tout le tampon, vous obtiendrez des résultats indésirables, vous devez donc aligner les pièces à la fois.
Malabarba
3

Mode marionnette fournit puppet-align-block. Vous pouvez faire en sorte que cette fonction soit appelée automatiquement, par exemple en l'ajoutant à post-command-hooklocalement (non testé):

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

Notez cependant qu'il y a une bonne raison de ne pas le faire. Ce n'est pas particulièrement intelligent, et écrasera tout alignement manuel que vous pourriez faire n'importe où, ce qui se cassera particulièrement mal, si l'alignement automatique ne fonctionne pas pour un code Puppet plus compliqué.

Par conséquent, en tant que responsable du mode Puppet, je le déconseille et nous ne vous aiderons pas ou n'accepterons pas les rapports de bogues si vous utilisez ce code.

En outre, pour les blocs de ressources volumineux, cela peut être lent, vous voudrez donc probablement utiliser un minuteur inactif au lieu de le faire post-command-hookdirectement.

lunaryorn
la source