Générer une liste de a à z dans emacs

Le problème

Un exercice intéressant a été posté par Xah Lee : http://www.ergoemacs.org/misc/emacs_exercise_gen_a-z.html

Le but est de générer le code suivant :

(global-set-key (kbd "<menu> g a") "A")
(global-set-key (kbd "<menu> g b") "B")
…
(global-set-key (kbd "<menu> g y") "Y")
(global-set-key (kbd "<menu> g z") "Z")

Clairement, la difficulté vient bien entendu de la génération a-zA-Z.

Mes solutions

Je me suis demandé si c'était possible de générer ça avec une macro. Puis y étant arrivé, je me suis dit qu'il fallait que je le fasse en elisp. Et je me suis souvenu qu'on pouvait mettre du elisp dans les regexp…

Sans elisp

Je me suis dit que faire une solution seulement avec une macro ça pourrait être sympa : Ma solution dans view-lossage (C-h l) :

C-x C-k C-f % c <return> <escape> 9 7 <f3>
( g l o b a l - s e t - k e y SPC ( k b d SPC " < m
e n u > SPC g SPC <escape> - 3 2 <f3> " ) SPC " <escape>
3 3 <f3> " ) <return> <f4> <escape> 2 5 <f4>

Plus clairement :

  1. on redéfinit le compteur de macro (C-x C-k C-f) en lui disant de prendre les caractères (%c) ;
  2. on débute la macro en initialisant le compteur à 97 (M-97 <f3>) qui correspond au code ascii de a ;
  3. on commence notre ligne (@<code>(global-set-key (kbd "<menu> g @</code>) ;
  4. on insère le compteur (a) en disant que le pas de comptage est de -32 (M--32 <f3>), donc le prochain sera A ;
  5. on continue notre ligne (@<code>") "@</code>) ;
  6. on insère le compteur (A) en disant que le pas de comptage est maintenant de 33 (M-33 <f3>), donc le prochain sera b ;
  7. on finit notre ligne et on va à la ligne (@<code>")<return>@</code>) ;
  8. on termine la macro (<f4>) ;
  9. on exécute la macro 25 fois (M-25 <f4>).

Un peu d'elisp

En utilisant les chercher/remplacer avec expression régulière (C-M-%), on peut insérer du code elisp en utilisant @<code>\,@</code> dans l'expression régulière.

On commence donc par créer une liste de 26 lignes (<f3> <f3> <return> <f4> M-25 <f4>). (Attention à bien être repassé au compteur « normal » (C-x C-k C-f %d).) Puis on se met au début du buffer (M-<).

Enfin on remplace ^\(.+\)$ par debut \,(string (+ ?a (string-to-number \1))) milieu \,(string (+ ?A (string-to-number \1))) fin (avec C-M-%).

Beaucoup d'elisp

On se met la fonction suivante quelque part, on se place après, on tape C-x C-e, puis M-x az là où on veut mettre notre liste.

(defun az()
  "liste az"
  (interactive)
  (let ((c 97))
  (while (< c 123)
    (insert (concat "debut " (string c) " milieu " (capitalize (string c))" fin" ))
    (newline)
    (setq c (+ c 1)))))

Le principe étant le même qu'avec les regexp, je ne commenterai pas :þ

Autres façons

Bien sûr, il y a tout un tas d'autres façons de faire. On peut combiner tout ça, utiliser du (format "%c" unNombre) plutôt que (string c) par exemple.

Pour les regexp, on n'est même pas obligé d'utiliser un compteur (et donc les macros). Il suffit d'insérer 26 lignes (M-26 <return>), de revenir au début du buffer (ou C-x C-x si on n'est pas au début du buffer et qu'on a activé la « marque » avec C-SPC), et de remplacer ^$ par \,(concat (string (+ ?a \#)) (string (+ ?A \#))) (oui, plus ça va, plus les lignes sont courtes). Le \# étant le nombre de remplacements déjà effectués.

Edit : autres solutions

J'ai encore du boulot en elisp… jcs @irreal propose une solution bien plus élégante (j'me disais bien qu'il y avait moyen de faire une boucle for):

(dotimes (c 26)
  (insert (format "(global-set-key (kbd \"<menu> g %c\") \"%c\")\n"
                  (+ ?a c) (+ ?A c))))
Autres billets

Date: <2013-01-23>

Generated by Emacs 24.3.1 (Org mode 8.2.4) - Show Org source (htmlized)

CSS inspired by Tontof, colors by Chaotic Soul

Validate