Livre de chevet du développeur FreeBSD
Précédent | Chapitre 5. Outils de programmation | Suivant

# 5.7. Utiliser Emacs comme environnement de développement

## 5.7.1. Emacs

Malheureusement, les systèmes Unix ne sont pas fournis avec des sortes d'environnements de développement intégrés tout-ce-que-vous-avez-toujours-voulu-et-beaucoup-plus-dans-un-ensemble-gigantesque que d'autres sytèmes ont. [1] Toutefois, il est possible de se faire son propre environnement. Cela n'est pas forcément aussi joli et il peut ne pas être autant intégré mais vous pouvez le personnaliser comme vous voulez. Et c'est gratuit. Et vous en avez les sources.

La clé de tout cela est Emacs. Maintenant il y a des gens qui le détestent, mais beaucoup l'aiment. Si vous êtes un du premier groupe, j'ai peur que cette section ait peu d'intérêt pour vous. Vous aurez besoin d'une quantité moyenne de mémoire pour le faire fonctionner--Je recommenderai 8Mo en mode texte et 16Mo dans X pour avoir un minimum de performances.

Emacs est basiquement un éditeur hautement personnalisable --en effet, il a été personnalisé au point de ressembler plus à un système d'exploitation qu'à un éditeur! Beaucoup de développeurs et d'administrateurs système passent en fait pratiquement tout leur temps à travailler dans Emacs, en ne le quittant qu'à leur déconnexion.

Il est impossible de dire tout ce qu'Emacs peut faire ici, mais voici quelques unes des caractéristiques d'intérêt pour les développeurs:

- Un très puissant éditeur, permettant le chercher-remplacer sur les chaînes et les expressions régulières (motifs), sauter à la fin ou au début d'un bloc, etc, etc.

- Menus déroulants et aide en ligne.

- Colorisation syntaxique en fonction du langage et indentation.

- Totalement personnalisable.

- Vous pouvez compiler et déverminer des programmes dans Emacs.

- Sur erreur de compilation, vous pouvez aller directement à la ligne de code source fautive.

- Une interface amicale au programme `info` utilisé pour lire la documentation hypertexte GNU, incluant la documentation sur Emacs elle-même.

- Une interface agréable à `gdb`, vous permettant de voir le code source au fur et à mesure que vous vous déplacez dans votre programme.

- Vous pouvez lire les nouvelles Usenet et envoyer des e-mails pendant que votre programme est en compilation.

Et sans doute beaucoup plus que je n'ai survolé.

Emacs peut être installé sur FreeBSD en utilisant Emacs le logiciel porté Emacs.

Une fois installé, démarrez-le et faites `C-h t` pour lire un cours sur Emacs--cela signifie maintenir la touche control, presser h, relâcher la touche control et presser t. (Alternativement, vous pouvez utiliser la souris pour sélectionner Emacs Tutorial dans le menu Help).

Bien que Emacs possède des menus, il est valable d'apprendre les raccourcis clavier, étant plus rapide quand vous éditez quelque chose d'appuyer sur un couple de touches que de reprendre la souris et de cliquer au bon endroit. Et, quand vous discutez avec des utilisateurs expérimentés d'Emacs, vous trouverez qu'ils parlent souvent de choses comme `M-x replace-s RET foo RET bar RET` aussi il est utile de savoir ce que cela veut dire. Et dans tous les cas, Emacs possède beaucoup trop de fonctions pour qu'elles soient dans les barres de menus.

Heureusement, il est assez simple de récupérer les raccourcis clavier car ils sont affichés à côté des éléments des menus déroulants. Mon conseil est d'utiliser un élément de menu pour, disons, ouvrir un fichier jusqu'à ce que vous sachiez comment cela fonctionne et que quand vous vous sentez à l'aise avec, essayez `C-x C-f`. Quand vous serez content avec ça, passez à une autre commande du menu.

Si vous ne pouvez pas vous rappeler de ce qu'une combinaison de touches particulières fait, sélectionnez Describe Key dans le menu Help et tapez-la--Emacs vous dira ce qu'elle fait. Vous pouvez aussi utiliser l'élément de menu Command Apropos pour trouver toutes les commandes qui contiennent un mot particulier, avec leur raccourci clavier.

De cette manière, l'expression ci-dessus signifie maintenir la touche Meta, taper x, relâcher la touche Meta, taper `replace-s` (raccourci pour `replace-string`-- une autre caractéristique d'Emacs est que vous pouvez abréger les commandes), appuyer sur la touche Entrée, taper `foo` (la chaîne que vous voulez remplacer), presser la touche Entrée, taper `bar` (la chaîne que vous voulez substituer à `foo`) puis appuyer sur Entrée une dernière fois. Emacs va alors faire l'opération chercher-remplacer que vous avez demandé.

Si vous vous demandez ce qu'est cette touche Meta, il s'agit d'une touche spéciale que beaucoup de stations de travail Unix possèdent. Malheureusement, les PC n'en ont pas, aussi c'est habituellement la touche alt (ou si vous n'avez pas de chance, la touche échap).

Oh, et pour sortir d'Emacs, faites `C-x C-c` (ce qui signifie maintenir la touche control appuyée, appuyer c et relâcher la touche control. Si vous avez des fichiers non sauvegardés ouverts, Emacs vous demandera si vous voulez les sauvegarder. (Ignorez le bout de documentation où il est dit que `C-z` est la manière habituelle de quitter Emacs-- qui quitte Emacs en le laissant tourner en tâche de fond et qui n'est vraiment utile que si vous avez un système sans terminal virtuel).

## 5.7.2. Configurer Emacs

Emacs fait des choses merveilleuses; une partie est intégrée directement, une autre doit être configurée.

Plutôt que d'utiliser un macro langage propriétaire pour la configuration, Emacs utilise une version du Lisp spécialement adaptée pour les éditeurs, connue sous le nom d'Emacs Lisp. Celui-ci peut être assez utile si vous voulez poursuivre et apprendre quelque chose comme le Common Lisp, car il est considérablement plus petit que le Common Lisp (bien que déjà assez gros!).

La meilleure façon d'apprendre l'Emacs Lisp est de télécharger le cours d'Emacs

Toutefois, il n'y a pas besoin de connaître le Lisp pour commencer la configuration d'Emacs, car j'ai inclus un exemple de fichier `.emacs` qui devrait être suffisant pour commencer. Copiez juste celui-ci dans votre répertoire utilisateur et redémarrez Emacs si celui-ci s'exécute, il lira les commandes du fichier et (si tout va bien!) vous donnera une configuration basique utile.

## 5.7.3. Un fichier exemple `.emacs`

Malheureusement, il y a beaucoup trop de choses ici pour les expliquer en détail; toutefois, il y a un ou deux points qui valent d'être mentionnés.

- Tout ce qui commence avec un `;` est un commentaire et est ignoré par Emacs.

- A la première ligne, le `-*- Emacs-Lisp -*-` est tel que vous pouvez éditer le fichier `.emacs` lui-même à l'intérieur d'Emacs et d'obtenir tous les fantaisistes dispositifs pour l'édition en Emacs Lisp. Emacs essaye habituellement de deviner cela en se basant sur le nom du fichier, et ne trouvera peut-être pas pour `.emacs`.

- La touche tab est liée à la fonction d'indentation dans certains modes, aussi quand vous l'enfoncez, cela va indenter la ligne courante de code. Si vous voulez mettre un caractère tab dans quoique ce soit que vous tapiez, maintenez la touche control enfoncée pendant que vous appuyez sur tab.

- Ce fichier supporte la colorisation de syntaxe pour les langages C, C++, Perl, Lisp et Scheme en devinant le langage par leur nom.

- Emacs possède déjà une fonction pré-définie appelée `next-error`. Dans la fenêtre de sortie d'une compilation, cela vous permet de vous déplacer d'une erreur de compilation à la suivante en faisant `M-n`; nous définissons une fonction complémentaire `previous-error`, qui vous permet d'aller à l'erreur précédente en faisant `M-p`. Le plus beau dispositif de tous est que `C-c C-c` va ouvrir le fichier source dans lequel l'erreur a eu lieu et sautera à la ligne appropriée.

- Nous autorisons la capacité d'Emacs à agir comme un serveur ainsi si vous faites quelque chose en dehors d'Emacs et voulez éditer un fichier, tapez juste

      % emacsclient nomfichier

  et alors vous pouvez éditer le fichier dans votre Emacs! [2]

Exemple 5-1. Un fichier exemple `.emacs`

    ;; -*-Emacs-Lisp-*-

    ;; Ce fichier est concu pour etre reevalue, utiliser la variable first-time
    ;; pour eviter tout probleme.
    (defvar first-time t
      "Valeur signifiant que c'est la premiere fois que .emacs a ete evalue"
      )

    ;; Meta
    (global-set-key "\M- " 'set-mark-command)
    (global-set-key "\M-\C-h" 'backward-kill-word)
    (global-set-key "\M-\C-r" 'query-replace)
    (global-set-key "\M-r" 'replace-string)
    (global-set-key "\M-g" 'goto-line)
    (global-set-key "\M-h" 'help-command)

    ;; Function keys
    (global-set-key [f1] 'manual-entry)
    (global-set-key [f2] 'info)
    (global-set-key [f3] 'repeat-complex-command)
    (global-set-key [f4] 'advertised-undo)
    (global-set-key [f5] 'eval-current-buffer)
    (global-set-key [f6] 'buffer-menu)
    (global-set-key [f7] 'other-window)
    (global-set-key [f8] 'find-file)
    (global-set-key [f9] 'save-buffer)
    (global-set-key [f10] 'next-error)
    (global-set-key [f11] 'compile)
    (global-set-key [f12] 'grep)
    (global-set-key [C-f1] 'compile)
    (global-set-key [C-f2] 'grep)
    (global-set-key [C-f3] 'next-error)
    (global-set-key [C-f4] 'previous-error)
    (global-set-key [C-f5] 'display-faces)
    (global-set-key [C-f8] 'dired)
    (global-set-key [C-f10] 'kill-compilation)

    ;; Keypad bindings
    (global-set-key [up] "\C-p")
    (global-set-key [down] "\C-n")
    (global-set-key [left] "\C-b")
    (global-set-key [right] "\C-f")
    (global-set-key [home] "\C-a")
    (global-set-key [end] "\C-e")
    (global-set-key [prior] "\M-v")
    (global-set-key [next] "\C-v")
    (global-set-key [C-up] "\M-\C-b")
    (global-set-key [C-down] "\M-\C-f")
    (global-set-key [C-left] "\M-b")
    (global-set-key [C-right] "\M-f")
    (global-set-key [C-home] "\M-<")
    (global-set-key [C-end] "\M->")
    (global-set-key [C-prior] "\M-<")
    (global-set-key [C-next] "\M->")

    ;; Souris
    (global-set-key [mouse-3] 'imenu)

    ;; Divers
    (global-set-key [C-tab] "\C-q\t")	; Control tab quotes a tab.
    (setq backup-by-copying-when-mismatch t)

    ;; Traite 'y' ou <CR> comme yes, 'n' comme no.
    (fset 'yes-or-no-p 'y-or-n-p)
        (define-key query-replace-map [return] 'act)
        (define-key query-replace-map [?\C-m] 'act)

    ;; Charge les ajouts
    (require 'desktop)
    (require 'tar-mode)

    ;; Diff mode sympa
    (autoload 'ediff-buffers "ediff" "Intelligent Emacs interface to diff" t)
    (autoload 'ediff-files "ediff" "Intelligent Emacs interface to diff" t)
    (autoload 'ediff-files-remote "ediff"
      "Intelligent Emacs interface to diff")

    (if first-time
        (setq auto-mode-alist
    	  (append '(("\\.cpp$" . c++-mode)
    		    ("\\.hpp$" . c++-mode)
                        ("\\.lsp$" . lisp-mode)
    		    ("\\.scm$" . scheme-mode)
    		    ("\\.pl$" . perl-mode)
    		    ) auto-mode-alist)))

    ;; Mode de verrouillage automatique de la police de caracteres
    (defvar font-lock-auto-mode-list
      (list 'c-mode 'c++-mode 'c++-c-mode 'emacs-lisp-mode 'lisp-mode 'perl-mode 'scheme-mode)
      "List of modes to always start in font-lock-mode")

    (defvar font-lock-mode-keyword-alist
      '((c++-c-mode . c-font-lock-keywords)
        (perl-mode . perl-font-lock-keywords))
      "Associations between modes and keywords")

    (defun font-lock-auto-mode-select ()
      "Automatically select font-lock-mode if the current major mode is
    in font-lock-auto-mode-list"
      (if (memq major-mode font-lock-auto-mode-list)
          (progn
    	(font-lock-mode t))
        )
      )

    (global-set-key [M-f1] 'font-lock-fontify-buffer)

    ;; New dabbrev stuff
    ;(require 'new-dabbrev)
    (setq dabbrev-always-check-other-buffers t)
    (setq dabbrev-abbrev-char-regexp "\\sw\\|\\s_")
    (add-hook 'emacs-lisp-mode-hook
    	  '(lambda ()
    	     (set (make-local-variable 'dabbrev-case-fold-search) nil)
    	     (set (make-local-variable 'dabbrev-case-replace) nil)))
    (add-hook 'c-mode-hook
    	  '(lambda ()
    	     (set (make-local-variable 'dabbrev-case-fold-search) nil)
    	     (set (make-local-variable 'dabbrev-case-replace) nil)))
    (add-hook 'text-mode-hook
    	  '(lambda ()
    	     (set (make-local-variable 'dabbrev-case-fold-search) t)
    	     (set (make-local-variable 'dabbrev-case-replace) t)))

    ;; mode C++ et C...
    (defun my-c++-mode-hook ()
      (setq tab-width 4)
      (define-key c++-mode-map "\C-m" 'reindent-then-newline-and-indent)
      (define-key c++-mode-map "\C-ce" 'c-comment-edit)
      (setq c++-auto-hungry-initial-state 'none)
      (setq c++-delete-function 'backward-delete-char)
      (setq c++-tab-always-indent t)
      (setq c-indent-level 4)
      (setq c-continued-statement-offset 4)
      (setq c++-empty-arglist-indent 4))

    (defun my-c-mode-hook ()
      (setq tab-width 4)
      (define-key c-mode-map "\C-m" 'reindent-then-newline-and-indent)
      (define-key c-mode-map "\C-ce" 'c-comment-edit)
      (setq c-auto-hungry-initial-state 'none)
      (setq c-delete-function 'backward-delete-char)
      (setq c-tab-always-indent t)
    ;; Style d'indentation BSD
      (setq c-indent-level 4)
      (setq c-continued-statement-offset 4)
      (setq c-brace-offset -4)
      (setq c-argdecl-indent 0)
      (setq c-label-offset -4))

    ;; mode Perl
    (defun my-perl-mode-hook ()
      (setq tab-width 4)
      (define-key c++-mode-map "\C-m" 'reindent-then-newline-and-indent)
      (setq perl-indent-level 4)
      (setq perl-continued-statement-offset 4))

    ;; mode Scheme...
    (defun my-scheme-mode-hook ()
      (define-key scheme-mode-map "\C-m" 'reindent-then-newline-and-indent))

    ;; mode Emacs-Lisp...
    (defun my-lisp-mode-hook ()
      (define-key lisp-mode-map "\C-m" 'reindent-then-newline-and-indent)
      (define-key lisp-mode-map "\C-i" 'lisp-indent-line)
      (define-key lisp-mode-map "\C-j" 'eval-print-last-sexp))

    ;; Ajoute tout le reste...
    (add-hook 'c++-mode-hook 'my-c++-mode-hook)
    (add-hook 'c-mode-hook 'my-c-mode-hook)
    (add-hook 'scheme-mode-hook 'my-scheme-mode-hook)
    (add-hook 'emacs-lisp-mode-hook 'my-lisp-mode-hook)
    (add-hook 'lisp-mode-hook 'my-lisp-mode-hook)
    (add-hook 'perl-mode-hook 'my-perl-mode-hook)

    ;; Le complement a next-error
    (defun previous-error (n)
      "Visit previous compilation error message and corresponding source code."
      (interactive "p")
      (next-error (- n)))

    ;; Divers...
    (transient-mark-mode 1)
    (setq mark-even-if-inactive t)
    (setq visible-bell nil)
    (setq next-line-add-newlines nil)
    (setq compile-command "make")
    (setq suggest-key-bindings nil)
    (put 'eval-expression 'disabled nil)
    (put 'narrow-to-region 'disabled nil)
    (put 'set-goal-column 'disabled nil)

    ;; Recherche des archives Elisp
    (autoload 'format-lisp-code-directory "lispdir" nil t)
    (autoload 'lisp-dir-apropos "lispdir" nil t)
    (autoload 'lisp-dir-retrieve "lispdir" nil t)
    (autoload 'lisp-dir-verify "lispdir" nil t)

    ;; Mode de verrouillage de police
    (defun my-make-face (face colour &optional bold)
      "Create a face from a colour and optionally make it bold"
      (make-face face)
      (copy-face 'default face)
      (set-face-foreground face colour)
      (if bold (make-face-bold face))
      )

    (if (eq window-system 'x)
        (progn
          (my-make-face 'blue "blue")
          (my-make-face 'red "red")
          (my-make-face 'green "dark green")
          (setq font-lock-comment-face 'blue)
          (setq font-lock-string-face 'bold)
          (setq font-lock-type-face 'bold)
          (setq font-lock-keyword-face 'bold)
          (setq font-lock-function-name-face 'red)
          (setq font-lock-doc-string-face 'green)
          (add-hook 'find-file-hooks 'font-lock-auto-mode-select)

          (setq baud-rate 1000000)
          (global-set-key "\C-cmm" 'menu-bar-mode)
          (global-set-key "\C-cms" 'scroll-bar-mode)
          (global-set-key [backspace] 'backward-delete-char)
    					;      (global-set-key [delete] 'delete-char)
          (standard-display-european t)
          (load-library "iso-transl")))

    ;; X11 ou PC utilisant les ecritures directes a l'ecran
    (if window-system
        (progn
          ;;      (global-set-key [M-f1] 'hilit-repaint-command)
          ;;      (global-set-key [M-f2] [?\C-u M-f1])
          (setq hilit-mode-enable-list
    	    '(not text-mode c-mode c++-mode emacs-lisp-mode lisp-mode
    		  scheme-mode)
    	    hilit-auto-highlight nil
    	    hilit-auto-rehighlight 'visible
    	    hilit-inhibit-hooks nil
    	    hilit-inhibit-rebinding t)
          (require 'hilit19)
          (require 'paren))
      (setq baud-rate 2400)			; For slow serial connections
      )

    ;; Terminal de type TTY
    (if (and (not window-system)
    	 (not (equal system-type 'ms-dos)))
        (progn
          (if first-time
    	  (progn
    	    (keyboard-translate ?\C-h ?\C-?)
    	    (keyboard-translate ?\C-? ?\C-h)))))

    ;; Sous Unix
    (if (not (equal system-type 'ms-dos))
        (progn
          (if first-time
    	  (server-start))))

    ;; Add any face changes here
    (add-hook 'term-setup-hook 'my-term-setup-hook)
    (defun my-term-setup-hook ()
      (if (eq window-system 'pc)
          (progn
    ;;	(set-face-background 'default "red")
    	)))

    ;; Restaure le  "desktop" - faire cela le plus tard possible
    (if first-time
        (progn
          (desktop-load-default)
          (desktop-read)))

    ;; Indique que ce fichier a ete lu au moins une fois
    (setq first-time nil)

    ;; Pas besoin de deverminer quoique ce soit maintenant

    (setq debug-on-error nil)

    ;; Tout est fait
    (message "All done, %s%s" (user-login-name) ".")

## 5.7.4. Etendre la palette de langages qu'Emacs comprend

Maintenant, Emacs est très bien si vous voulez seulement programmer dans des langages déjà fournis dans le fichier `.emacs` (C, C++, Perl, Lisp et Scheme), mais qu'arrive-t-il si un nouveau langage appelé whizbang sort, plein d'excitantes fonctionnalités ?

La première chose à faire est de savoir si whizbang est fourni avec des fichiers de configuration pour Emacs. Ceux-ci se terminent habituellement par `.el`, raccourci pour Emacs Lisp. Par exemple, si whizbang est un logiciel porté FreeBSD, nous pouvons localiser ces fichiers en faisant

    % find /usr/ports/lang/whizbang -name "*.el" -print

et les installer en les copiant dans le répertoire Lisp d'Emacs. Sur FreeBSD 2.1.0-RELEASE, il s'agit de `/usr/local/share/emacs/site-lisp` [3].

Aisni par exemple, si la sortie de la commande `find` était

    /usr/ports/lang/whizbang/work/misc/whizbang.el

nous ferions

    # cp /usr/ports/lang/whizbang/work/misc/whizbang.el /usr/local/share/emacs/site-lisp

Ensuite, nous devons décider quel extension les fichiers source whizbang ont. Disons qu'il s'agit de fichiers se terminant par `.wiz`. Nous devons ajouter une entrée dans notre fichier `.emacs` pour être sûr qu'Emacs sera capable d'utiliser les informations dans `whizbang.el`.

Trouvez l'entrée `auto-mode-alist` dans `.emacs` et ajoutez une ligne pour whizbang, comme :

    ...
    ("\\.lsp$" . lisp-mode)
    ("\\.wiz$" . whizbang-mode)
    ("\\.scm$" . scheme-mode)
    ...

Cela signifie qu'Emacs ira automatiquement dans la fonction `whizbang-mode` quand vous éditerez un fichier se terminant par `.wiz`.

Juste en-dessous, vous trouverez l'entrée `font-lock-auto-mode-list`. Ajoutez `whizbang-mode` à celle-ci comme ceci :

    ;; Auto font lock mode
    (defvar font-lock-auto-mode-list
      (list 'c-mode 'c++-mode 'c++-c-mode 'emacs-lisp-mode 'whizbang-mode 'lisp-mode 'perl-mode 'scheme-mode)
      "List of modes to always start in font-lock-mode")

Cela signifie qu'Emacs autorisera toujours `font-lock-mode` (ie colorisation de la syntaxe) pendant l'édition d'un fichier `.wiz`.

Et c'est tout ce qui est nécessaire. S'il y a quoique ce soit que vous voulez de fait automatiquement quand vous ouvrez un fichier `.wiz`, vous pouvez ajouter un `whizbang-mode hook` (voir `my-scheme-mode-hook` pour un exemple simple qui ajoute `auto-indent`, l'auto-indentation).

### Notes

[1] | Sauf si vous payez des sommes importantes.
[2] | Beaucoup d'utilisateurs d'Emacs mettent leur variable d'environnement `EDITOR` à `emacsclient` ainsi cela se passe à chaque fois qu'ils ont besoin d'éditer un fichier.
[3] | NDT : Sur FreeBSD 4.2-RELEASE aussi.

Précédent | Sommaire | Suivant
Déverminer | Niveau supérieur | Pour aller plus loin

Ce document, ainsi que d'autres peut être téléchargé sur ftp.FreeBSD.org/pub/FreeBSD/doc/.

Pour toutes questions à propos de FreeBSD, lisez la documentation avant de contacter <questions@FreeBSD.org>.
Pour les questions sur cette documentation, contactez <doc@FreeBSD.org>.