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:

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.

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.

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>.

Hosting by: Hurra Communications GmbH
Generated: 2007-01-26 18:01:12