Ré-indentation automatique du code elisp lors de l'ajout ou de la suppression de code avant un bloc indenté

18

Disons que j'ai un code elisp comme:

(+ 2 3▮(+ 3
          4))

Existe-t-il un moyen de ré-indenter automatiquement le sexp après le curseur, lorsque j'ajoute ou supprime des symboles?

Donc, après avoir appuyé sur SPC 4 SPC, j'obtiendrais automatiquement:

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

Je peux faire ce manuel en appelant mark-sexpsuivi de indent-region. Y a-t-il de meilleures façons de procéder?

Maciej Goszczycki
la source
Je ne pense pas qu'il existe de raccourcis clavier par défaut, mais vous pouvez facilement en créer vous-même.
shosti
Je sais, mais je me demande précisément s'il existe de meilleures façons de procéder. Par exemple, comment electric-indent-modeest bien meilleur que le mappage <return>versnewline-and-indent
Maciej Goszczycki

Réponses:

14

Au lieu de mark-sexp+ indent-region, vous pouvez appuyer sur C-M-q. Cela va appeler indent-pp-sexp. Pas automatique, mais un peu mieux que d'avoir à invoquer deux commandes.

Ou si vous utilisez paredit-mode, appuyez sur M-q. Cela réindentera toute la définition de fonction dans laquelle vous vous trouvez.

Dmitry
la source
1
(add-hook 'post-self-insert-hook 'indent-pp-sexp)fonctionne bien surprenant.
Maciej Goszczycki
Cela semble bon. Cela peut être coûteux dans certains modes, mais c'est quand même une bonne approche.
Dmitry
Pour les utilisateurs de Smartparens, vous pouvez réactiver le defun actuel avec M-x sp-indent-defun. Je lie cela à C-M-q.
Radon Rosborough
15

Mode de retrait agressif

Depuis que certaines personnes l'ont demandé, j'ai transformé cette réponse en un package .

Si vous avez configuré Melpa, vous pouvez l'installer avec

M-x package-install RET aggressive-indent

Consultez le fichier Lisez - moi pour toutes les options, mais le moyen le plus simple de l'activer est:

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

L'ancienne réponse

Ce qui suit effectue l'indentation automatique uniquement sur les tampons elisp. Il a l'avantage de fonctionner également lorsque vous effacez ou tirez des trucs (au lieu de simplement taper). Il est également facile d'ajouter à d'autres modes.

Cette fonction indentera toute expression s dans laquelle le point se trouve actuellement. Vous pouvez le lier à une clé si vous le souhaitez, mais voyez d'abord ci-dessous.

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

Ce crochet fera en sorte que cette fonction sera exécutée après avoir tapé quoi que ce soit, mais uniquement dans les tampons elisp. Cela devrait garder tout toujours en retrait.

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

Essayez! Cela fonctionne remarquablement bien.

En outre, en suivant la suggestion de @ holocronweaver dans les commentaires, vous pouvez utiliser quelque chose comme ce qui suit pour les langages de type c:

(define-key c++-mode-map ";"
  (lambda () (interactive)
    (insert ";")
    (endless/indent-defun)))
Malabarba
la source
Ce serait excellent si cela réduisait au silence les messages d'indentation automatique et les langues mieux gérées qui terminent les lignes par des points-virgules.
holocronweaver
@holocronweaver bien sûr, je peux essayer ça. Quel mode principal comporte des messages de retrait? Et quel est le problème avec les points-virgules?
Malabarba
Tous les modes que j'ai essayés sur le tronc Emacs ont produit des messages de retrait, y compris elisp. Étant donné que les points-virgules terminent une ligne dans de nombreuses langues, jusqu'à ce que vous tapiez le point-virgule, la ligne suivante saute comme si elle faisait partie de la ligne actuelle.
holocronweaver
@holocronweaver Réduit au silence les messages. Merci de l'avoir signalé.
Malabarba
Merci pour le correctif! Une solution au problème de point-virgule consiste à ne mettre en retrait que dans les langues en mode c lorsqu'un point-virgule est tapé.
holocronweaver du
3

Je ne connais pas de solution préexistante, mais vous pouvez l'utiliser post-self-insert-hookpour y parvenir vous-même:

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

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

Je m'inquiéterais cependant des problèmes de performances potentiels.

shosti
la source
1

Vous pouvez essayer le mode el-fly-indent , qui se comporte mieux que aggressive-indent-modelorsque vous traitez avec Elisp.

Jiahao
la source