Écrire du code C avec Emacs
Et de deux ! —rz0
Cet article d’introduction s’intéresse aux aspects basiques liés à l’écriture et à la gestion du code C basique avec Emacs, et, bien sûr, aux fonctionnalités qui vous y aideront.
Édition du code avec le c-mode
Le mode d’édition du code C dans Emacs se nomme très simplement le
c-mode et est inclus par défaut avec l’éditeur ; vous pouvez aussi
obtenir la dernière version du mode (qui est développé en dehors
d’Emacs lui-même) sur le site du cc-mode. Le c-mode offre
plusieurs fonctionnalités et commandes intéressantes.
Indentation automatique
Tout d’abord, comme tous les modes de programmation dans Emacs, le
c-mode possède l’indentation automatique. Cela signifie que la
touche TAB (ou, de manière équivalente, C-i) n’est pas utilisée
pour insérer un caractère « tabulation » mais pour indenter la ligne
actuelle, c’est-à-dire aligner le début de celle-ci sur la colonne
adéquate, comme vous le feriez vous-même si Emacs n’était pas là. Il
est important de remarquer que cette opération ne tient absolument pas
compte de l’indentation actuelle de la ligne : qu’elle soit trop
décalée à gauche ou à droite, Emacs la replacera au bon endroit.
Emacs indentera la ligne selon deux informations : le contexte syntaxique (si vous êtes au début d’une instruction, au milieu d’un appel de fonction, etc.) et le style sélectionné (par exemple, K&R ou BSD ; voyez mon introduction à la configuration d’Emacs pour plus d’informations).
Comme il peut devenir lassant de devoir appuyer (quoique ce ne soit
qu’une seule fois) sur la touche TAB à chaque début de ligne, sachez
que vous pouvez aller à la ligne et indenter en une seule commande :
C-j (newline-and-indent).
Mais l’indentation d’Emacs ne se limite pas à la ligne actuelle !
Vous pouvez également lui demander d’indenter tout un bloc ou une
fonction pour vous. Il s’agit respectivement des commandes C-M-\
(indent-region) et C-c C-q (c-indent-defun), qui indentent la
région actuelle (la zone de texte située entre la marque, usuellement
apposée par C-SPC, et le curseur) et la fonction dans laquelle se
trouve le curseur. En théorie, vous pourriez indenter tout le fichier
ainsi, mais je vous le déconseille ; lalgorithme est lent et perd en
précision si les constructions sont trop vilaines ou complexes. En
revanche, si vous effectuez une modification au milieu d'un bloc, et
que, par exemple, vous supprimez un niveau d'indentation, ces
commandes peuvent s'avérer très utiles.
Parfois, en revanche, vous voulez aligner des éléments (comme le
ferait la toucheTABen temps normal) sans qu'Emacs n'essaie
d'indenter la ligne. Pour cela, vous pouvez utiliser la commandeM-i(tab-to-tab-stop). C'est le cas, par exemple, si vous alignez vos
déclarations ou vos instructions dans unswitch.
Pour résumer, voici un tableau des commandes d'indentation et
d'alignement :
|TAB | indente la ligne actuelle |
|C-j | retour à la ligne et indentation simultanés |
|C-M-‘ | indente la région actuelle
C-c C-q | indente la fonction actuelle |
M-i | aligne le curseur sur la prochaine colonne de tabulation |
Gestion des commentaires
De même qu’Emacs sait indenter le code automatiquement, il sait
insérer des commentaires au bon endroit ; pour se faire, il vous
suffit d’actionner la commande M-; (comment-dwim). Que vous soyez
sur une ligne vide ou non, Emacs déterminera la syntaxe
à adopter. C’est la commande idéale pour ceux qui trouvent les
commentaires de type C (/* ... */) trop longs à taper.
De plus, Emacs dispose des commandes de traitement de régions
suivantes : comment-region et uncomment-region. Elles sont
accessibles par M-x et qui peuvent être associées à une combinaison
de votre choix si vous en sentez le besoin. Je vous laisse deviner ce
qu’elles font. Elles peuvent être utiles à ceux qui aiment isoler des
morceaux de code avec des commentaires (personnellement, je préfère
utiliser #if 0).
M-; | insère un commentaire |
Déplacements contextuels
Enfin, le c-mode dispose de mécanismes de navigation
contextuelle. La plupart des commandes utilisées sont communes à tous
les modes d’édition mais leur fonctionnement a été adapté à la
structure du code C.
Vous pouvez, comme toujours, vous déplacer de mot en mot avec les
habituels M-b (backward-word) et M-f (forward-word).
Juste au niveau supérieur, les commandes C-M-b (backward-sexp) et
C-M-f (forward-sexp) vous permettent de sauter d’un bout à l’autre
d’expressions équilibrées (un groupe entre parenthèses, crochets ou
accolades). En complément, C-M-u (backward-up-list) et C-M-d
(down-list) naviguent à travers les niveaux de parenthésage :
C-M-u vous amène au début du groupe dans lequel se situe le curseur
et C-M-d vous transporte au début du prochain groupe à l’intérieur
de l’expression actuelle. Le plus simple est encore de les essayer
pour en voir les effets !
Vous pouvez également vous déplacer au début et à la fin des
instructions avec M-a (c-beginning-of-statement) et M-e
(c-end-of-statement), respectivement.
Enfin, les commandes beginning-of-defun et end-of-defun font, sans
surprise, le voyage au début et à la fin d’une définition de fonction.
Récapitulons les commandes directement accessibles :
C-b, C-f | déplacement au mot |
C-M-b, C-M-f | déplacement à l’expression (équilibrée) |
C-M-u, C-M-d | déplacement à l’expression (équilibrée) |
M-a, M-e | déplacement à l’instruction |
Plusieurs fichiers sources
Avec ce que nous venons juste de voir, nous sommes maintenant capables d’éditer un fichier source C. Toutefois, la plupart des projets ne sont pas constitués d’un seul fichier, aussi, nous allons nous pencher sur la gestion de plusieurs fichiers dans Emacs. Cette section n’est pas directement liée à la programmation en C, mais la question revient fréquemment chez les novices, et c’est pourquoi j’ai décidé de la traiter ici.
Hiérarchies de fichiers
Typiquement, le scénario est le suivant : vous possédez plusieurs
fichiers sources regroupés dans un dossier. Quelque chose que beaucoup
de gens aiment faire est pouvoir regarder la hiérarchie des fichiers
et naviguer de fichier en fichier. Pour cela, Emacs offre deux
mécanismes : dired, un explorateur de fichiers, et la speedbar,
une barre latérale.
Selon vos goûts, vous préférerez sans doute l’un ou l’autre. Les
différences sont multiples : dired possède plus de facilités pour la
gestion des hiérarchies de fichiers et de dossiers, avec toutes les
fonctions classiques que l’on pourrait attendre d’un explorateur de
fichiers, et se présente comme une application Emacs à part entière,
utilisant ses propres buffers. À l’opposé, la speedbar s’affiche
dans un cadre (frame) à part, et son contenu est constamment
recalculé de sorte que le dossier affiché dans la barre soit toujours
celui du fichier actuel.
Si vous n’êtes pas habitué à la terminologie emacsienne, sachez qu’une
fenêtre correspond à une division de l’affichage d’Emacs (ce que
vous obtenez avec C-x 2 par exemple) tandis qu’un cadre est un
ensemble de fenêtres indépendant, ce qui, en mode graphique,
correspond, pour la plupart des gestionnaires de fenêtres, à ce qu’ils
appellent une fenêtre. Sauf mention contraire, nous utiliserons ici
le vocabulaire d’Emacs.
À l’usage, l’un ou l’autre est assez naturel. Pour lancer dired,
utilisez la commande C-x d (dired) ou C-x C-f (find-file) avec
le chemin d’un dossier. Pour lancer la speedbar, tapez M-x
speedbar ; un cadre devrait apparaître à côté de votre cadre
principal.
Une fois à l’intérieur de l’un ou l’autre, placez-vous sur un fichier
et tapez RET (dired-advertised-find-file ou speedbar-edit-line)
pour le visiter. Sous dired, vous avez l’option de visiter le
fichier dans une autre fenêtre avec o
(dired-find-file-other-window).
Si vous voulez parcourir des sous-dossiers, sachez que dired prône
une disposition plane tandis que la speedbar affiche les dossiers et
les fichiers sous forme arborescente. Lorsque votre curseur est sur
une ligne correspondant à un sous-dossier, tapez i sous dired ou
+ dans la speedbar (respectivement, dired-maybe-insert-subdir et
speedbar-expand-line) pour insérer son listage dans le buffer
actuel. Pour supprimer l’affichage d’un sous-dossier, placez-vous sur
son en-tête (son chemin, juste au-dessus du listage, pour dired, ou
son nom dans l’arborescence, pour la speedbar) et exécutez la
commande M-x dired-kill-subdir ou - (speedbar-contract-line),
pour dired et la speedbar respectivement. Au lieu de l’effacer
complètement, dired vous propose aussi d’utiliser la commande $
(dired-hide-subdir), qui, malgré son nom, permet de cacher et de
découvrir le contenu du dossier.
Si votre gestionnaire de fenêtres ne vous permet pas de déplacer
facilement le focus au clavier, sachez qu’Emacs vous permet d’aller
de cadre en cadre avec C-x 5 o (other-frame).
Et comme précédemment, un petit récapitulatif :
dired | speedbar
| |
| parcourir un dossier | C-x d | automatique |
| visiter un fichier | RET | RET
|
| insérer un sous-dossier | i | +
|
| cacher un sous-dossier | $ | -
|
Plusieurs fichiers dans Emacs
Maintenant que vous savez accéder facilement à plusieurs fichiers de votre projet, vous risquez fort d’être vite submergé par le grand nombre de buffers ouverts. Emacs ne dispose pas de tabs (ce n’est pas comme si vous alliez vous servir de votre souris pour y accéder, de toute manière). En revanche, plusieurs modes sont disponibles pour gérer vos buffers. Je ne vais pas tous les passer en revue ici, je ne donnerai qu’une seule solution.
La première commande à connaître pour bien gérer vos multiples
buffers est sans doute C-x C-b (list-buffers). Elle démarre le
gestionnaire de buffers. Ce dernier se présente comme une simple
liste des buffers ouverts. Vous pouvez y effectuer les opérations de
navigation habituelles, dont la recherche (avec C-s
(isearch-forward) pour les étourdis). RET
(Buffer-menu-this-window) vous permet de visiter le buffer à la
ligne actuelle. Une autre utilisation très pratique est de supprimer
plusieurs buffers à la fois. Pour cela, marquez chaque buffer
à détruire avec la commande d (Buffer-menu-delete). La lettre D
apparaît alors à gauche du nom. La commande x
(Buffer-menu-execute) effectue l’opération de nettoyage en
elle-même. Ainsi, si vous vous êtes trompé dans votre marquage, vous
pouvez revenir en arrière en utilisant la commande u
(Buffer-menu-unmark) sur la même ligne.
Tout cela est bien utile pour faire le ménage mais ne vous aide guère
pour votre besoin le plus simple : naviguer de buffer en
buffer. Pour cela, il y a bien sûr la commande C-x b
(switch-to-buffer) par défaut d’Emacs pour changer de buffer. Mais
elle n’est pas très pratique ; en effet, elle demande d’entrer le
début du nom pour accéder au buffer. Fort heureusement, il existe
(au moins) un mode qui vous permet de changer de buffer en tapant
quelques lettres n’importe où dans le nom. Je vous présente là
l’iswitchb-mode. Pour l’essayer, il vous suffit d’effectuer la
commande M-x iswitchb-mode ; de même pour le désactiver. Pour
l’adopter définitivement, ajoutez à votre .emacs la ligne :
(iswitchb-mode t)
La combinaison C-x b invoquera à présent iswitchb-buffer. Si vous
l’essayez, vous remarquerez que la liste des buffers qui sont encore
candidats à la sélection est maintenant affichée à côté de votre
saisie. Dans ce mode, les commandes C-r (iswitchb-prev-match) et
C-s (iswitchb-next-match) vous permettent de faire défiler les
éléments de la liste de manière cyclique, et RET sélectionne le
premier buffer de la liste. Ainsi, vous n’aurez plus à taper le
début exact du nom que vous voulez, il vous suffira simplement
d’entrer quelques lettres remarquables et, moyennant quelques
rotations de la liste, vous arriverez rapidement à destination.
Vous pouvez aussi demander à utiliser des expressions régulières. La
commande C-t (iswitchb-toggle-regexp), dans l’iswitchb-mode,
vous permet cela. Par exemple, pour obtenir une liste des fichiers
C ouverts, vous pourriez utiliser le motif \.c$. Veuillez cependant
prendre note du fait que les expressions régulières d’Emacs diffèrent
d’autres syntaxes, soyez donc averti et pensez à lire le manuel (avec
C-h i (info), par exemple) si vous désirez en faire bon usage.
Avec l’habitude, ce système très flexible remplace avantageusement les tabs. Vous n’êtes plus lié à une liste prédéfinie ; vous avez la possibilité de fabriquer rapidement la vôtre, adaptée à votre requête. Du reste, il vous permettra de même d’aller de buffer en buffer. Et tout cela pour un encombrement nul dans vos autres actions !
Et pour les petits étourdis :
C-x C-b | gestionnaire de buffers |
C-x b | change de buffer |
C-r et C-s | défilement de la liste (dans iswitchb)
|
C-t | activation des regexps (dans iswitchb)
|
Édition simultanée de plusieurs fichiers
Bien sûr, vous n’êtes pas encore capable de vous dédoubler pour éditer plusieurs fichiers à la fois, mais parfois, vous pourriez vouloir afficher deux fichiers (voire plus) côte à côte.
Pour se faire, rien de plus simple. Il vous suffit de partager votre
affichage en deux : verticalement avec C-x 2
(split-window-vertically) ou horizontalement avec C-x 3
(split-window-horizontally). Pour passer d’une fenêtre à l’autre,
utilisez C-x o (other-window). Enfin, C-x 0 (delete-window) et
C-x 1 (delete-other-windows) vous permettent respectivement de
supprimer la fenêtre sur laquelle se trouve le focus et de ne laisser
qu’elle.
Ainsi, vous pourrez plus facilement comparer ou transférer du code d’un fichier à un autre.
Sachez également qu’il existe des commandes qui marient une action
donnée à un changement de fenêtre, telles queC-x 4 f
(find-file-other-window) et C-x 4 b
(switch-to-buffer-other-window). La première ouvre un fichier,
à l’instar de C-x C-f (find-file) mais l’affiche dans une fenêtre
séparée. La seconde agit comme C-x b (switch-to-buffer) mais, de
même, place le contenu dans une autre fenêtre. Si le cadre n’est
constitué que d’une fenêtre, celui-ci est automatiquement scindé en
deux.
C-x 2, C-x 3 | création de fenêtres |
C-x o | déplacement de fenêtre à fenêtre |
C-x 0, C-x 1 | suppression de fenêtres |
C-x 4 f | visite un fichier dans une autre fenêtre |
C-x 4 b | affiche un buffer dans une autre fenêtre |
Gestion de l’historique des modifications avec VC
Le dernier outil essentiel à tout projet sérieux est un gestionnaire de versions. Si vous n’êtes pas familier avec ce concept, voici une brève introduction. Vos fichiers seront amenés à grandement évoluer avec les phases d’essai, de correction, d’essais publics, d’amélioration, etc. Il est donc primordial de contrôler ces changements sous forme de versions. Des logiciels spécialisés appelés « systèmes de contrôle de versions » (VCS, Version Control Systems en anglais) permettent de faire cela. Nous n’entrerons pas ici dans le détail du fonctionnement de ceux-ci, mais le principe général est le suivant : chaque fichier est associé à une copie persistante, qui représente tous ses états depuis le début, toutes ses versions, sous forme de différences. Cela signifie qu’une version n’est pas stockée en entier mais uniquement sous une forme relative à une version voisine. Dans sa réalisation la plus classique, par exemple, si vous ajoutez une ligne à un fichier, le fichier de contrôle, contenant la copie persistante, enregistrera une différence d’une ligne par rapport à la version précédente.
Emacs intègre un support de certains de ces systèmes, dont RCS, CVS, SVN et Git. Pour illustrer cette intégration, qui porte le petit nom de VC pour, vous l’aurez deviné, Version Control, nous allons nous intéresser au plus simple d’entre eux : RCS. Mais les commandes demeurent approximativement les mêmes quel que soit le programme de gestion de versions.
Traditionnellement, les fichiers de contrôle de RCS sont stockés
localement dans un sous-dossier de celui où se situent vos fichiers
sources, ce sous-dossier portant le nom RCS. Si vous ne le créez pas
par vous-même, Emacs vous le proposera en temps voulu.
L’utilisation de VC repose sur la commande C-x v v
(vc-next-action). Comme son nom l’indique, elle fait… des choses,
selon l’état actuel du fichier. Avec RCS, un fichier peut avoir
plusieurs états. Dans son utilisation classique, ce sont les suivants.
Au départ, le fichier est inconnu de RCS. Lorsque vous l’enregistrez auprès de ce dernier (avec
C-x v v), celui-ci s’approprie le contenu. Le fichier et la version la plus récente connue de RCS sont alors les mêmes.À ce stade, vous ne pouvez pas modifier le fichier à nouveau. Il vous faut prévenir RCS de votre intention, ceci afin d’empêcher que plusieurs personnes ne modifient le même fichier en même temps. Cette action s’appelle le verrouillage et s’effectue aussi par
C-x v v. Une fois le fichier verrouillé, vous êtes sûr qu’il est la seule copie de travail existante.Une fois vos modifications effectuées,
C-x v vsynchronise votre brouillon avec la copie de contrôle. VC vous demande alors de fournir un commentaire décrivant les changements, commentaire qui sera inscrit dans une espèce de journal de bord du fichier. La fenêtre d’édition du message est tout à fait banale et la validation est obtenue par le traditionnelC-c C-c,valable pour la plupart des formulaires sous Emacs. Après cette étape, le fichier et la version la plus récente connue de RCS sont à nouveau les mêmes.
Tout ceci est bien joli, mais à quoi serviraient un historique et un journal que l’on ne peut consulter ?
La commande C-x v ~ (vc-version-other-window) vous permet
d’accéder au contenu d’une version antérieure de votre fichier. Le
numéro de la version vous sera demandé. Mais que faire si vous ne vous
rappelez plus de la bonne version ? C’est à cela que servent les
commentaires que vous avez pris soin d’entrer tout au long de votre
travail ! Pour voir la liste des versions ainsi que les messages
associés, tapez C-x v l (vc-print-log).
Une fois la version voulue récupérée dans un buffer secondaire, vous
pouvez afficher les deux buffers en parallèle comme nous avons vu
précédemment. Mais VC propose une commande intéressante pour vous
aider à voir les différences entre vos versions : C-x v =
(vc-diff). Elle vous propose une comparaison rapide de deux
versions, avec la différence placée dans un buffer à part.
Cela peut sembler beaucoup de choses à enregistrer si vous n’avez jamais utilisé de VCS auparavant, mais j’ai moi-même débuté dans ce domaine avec VC qui est, à mon avis, un moyen simple de se familiariser avec le concept tout en restant bien au chaud dans son éditeur préféré. Et pour vous y aider, voici un… récapitulatif ! Avouez que vous ne vous y attendiez pas.
C-x v v | change d’état |
C-x v ~ | ressuscite une version |
C-x v l | invoque la liste des versions |
C-x v = | compare deux versions |
Cette présentation de VC et de RCS achève ce premier article. Dans le
prochain chapitre (peut-être…α), nous parlerons de la compilation de
fichiers et de projets écrits en C, à l’aide de makefiles, le tout
depuis Emacs. Contrairement à ce premier tutoriel, il sera bien moins
porté sur Emacs lui-même que sur les outils à mettre en œuvre pour
compiler depuis Emacs, c’est-à-dire GCC et make.
α : L’histoire nous a montré que ce « peut-être » a su se transformer en « non ». :)
Je remercie Metzgermeister et nicofrand pour la relecture de cet article.
![[Atom]](feed.png)