;; -*- emacs-lisp -*-
;;
;; ===================================================================
;; Fichier ~/.emacs (fichier de configuration d'Emacs)
;; Sébastien Dinot <sebastien.dinot@free.fr>
;; Time-stamp: <2008-01-02 08:22:25>
;; ===================================================================
;;
;; ===================================================================
;;
;; Quelques commandes bien utiles que j'ai tendance à oublier à cause
;; des raccourcis que je définis :
;;
;; C-_ :
;;   Annulation de la dernière commande exécutée
;; C-x k :
;;   Clore un tampon d'édition (par défaut, le courant)
;; C-x C-right arrow :
;;   Passer au tampon d'édition suivant dans la liste
;; C-x C-left arrow :
;;   Passer au tampon d'édition précédent dans la liste
;; C-q <code ascii> RET :
;;   Insertion du caractère dont le code ASCII est indiqué à la suite
;;   de la séquence C-q. Par défaut, le code ASCII est exprimé en
;;   octal. Par exemple, pour insérer un espace insécable, dont le
;;   code ASCII est (0xa0 en hexa, 160 en décimal et 0240 en octal),
;;   il faut taper « C-q 2 4 0 RET ». Pour pouvoir fournir la valeur
;;   décimale, il faut modifier la variable read-quoted-char-radix :
;;   (setq read-quoted-char-radix 10)
;;   Ceci fait, pour insérer le même espace insécable, on tapera
;;   désormais « C-q 1 6 0 RET »
;; M-g g <numéro de ligne> RET :
;;   Positionner le curseur sur la ligne <numéro de ligne>.
;;
;; ===================================================================


;; Ajouter mon répertoire personnel à la liste des chemins de
;; recherche des modules.
(if (file-exists-p "~/elisp/")
  (setq load-path (cons (concat "~/elisp/") load-path))
)


;; Par défaut, lorsqu'Emacs est lancé dans un terminal, il ne s'adapte
;; pas à la configuration du terminal et du clavier et ne procède donc
;; à aucune conversion des entrées/sorties. Les lignes ci-dessous lui
;; demandent de le faire en se basant sur les locales.
(when (not window-system)
  (set-language-environment locale-coding-system)
  (set-keyboard-coding-system locale-coding-system)
  (set-terminal-coding-system locale-coding-system)
)


;; Mise en évidence des caractères invisibles tels que les espaces
;; normaux et insécables, les tabulations et les retours à la ligne,
;; les espaces insérés avant des tabulations et les espaces superflus
;; en fin de ligne.
(if (>= emacs-major-version 22)
  (progn
    ;; Mode à utiliser avec Emacs 22
    ;; http://emacswiki.org/cgi-bin/wiki/BlankMode
    (require 'blank-mode)
    ;; Le mode n'est pas actif par défaut, on l'active donc...
    (global-blank-mode-on)
    ;; ... y compris dans le mode texte où la coloration syntaxique
    ;; est inhibée par défaut
    (add-hook 'text-mode-hook 'blank-mode-on)
    ;; On met en évidence tous les caractères invisibles hormis les
    ;; fins de ligne (newline)
    (setq blank-chars '(tabs spaces trailing lines space-before-tab))
    ;; La mise en évidence se limite à une coloration, aucune
    ;; caractère de substitution (mark) n'est inséré.
    (setq blank-style '(color))
    ;; Style utilisé pour les espaces normaux (pas de mise en évidence)
    (set-face-background 'blank-space-face nil)
    (set-face-foreground 'blank-space-face "black")
    ;; Style utilisé pour les espaces insécables
    (set-face-background 'blank-hspace-face "PaleGreen")
    (set-face-foreground 'blank-hspace-face "black")
    ;; Style utilisé pour les espaces insérés à gauche d'une tabulation
    (set-face-background 'blank-space-before-tab-face "orange")
    (set-face-foreground 'blank-space-before-tab-face "black")
    ;; Style utilisé pour les tabulations
    (set-face-background 'blank-tab-face "lemonchiffon")
    (set-face-foreground 'blank-tab-face "black")
    ;; Style utilisé pour les espaces superflus en fin de ligne
    (set-face-background 'blank-trailing-face "gold")
    (set-face-foreground 'blank-trailing-face "black")
    ;; Style utilisé pour les lignes trop longues
    (set-face-background 'blank-line-face "snow2")
    (set-face-foreground 'blank-line-face "black")
  )
  (progn
    ;; Mode alternatif à utiliser avec les versions d'Emacs
    ;; antérieures à la version 22.
    ;; http://www.emacswiki.org/cgi-bin/wiki/show-wspace.el
    (require 'show-wspace)
    (add-hook 'font-lock-mode-hook 'show-ws-highlight-tabs)
    (add-hook 'font-lock-mode-hook 'show-ws-highlight-hard-spaces)
    (add-hook 'font-lock-mode-hook 'show-ws-highlight-trailing-whitespace)
  )
)

;; Conversion de l'encodage des données lors d'un copier / coller
;; depuis d'autres logiciels sous X.
;; La valeur « compound-text-with-extensions » fait disparaître le
;; problème des conversions de lettres accentuées :
;;   é => ^[%/1\200\214iso8859-15^B
;; Cette fonction n'existe qu'à partir de la version 21 d'Emacs.
(if (>= emacs-major-version 21)
  (setq selection-coding-system 'compound-text-with-extensions)
)


;; Lorsqu'une ligne est plus large que la fenêtre d'affichage, je veux
;; qu'Emacs me l'affiche sur autant de lignes que nécessaire plutôt
;; que de masquer la partie qui dépasse à droite de l'écran. Pour que
;; ce comportement vaille en toute circonstance, il est nécessaire de
;; fixer deux variables.
;; - truncate-lines : comportement dans un tampon occupant toute la
;;   largeur de la fenêtre
;; - truncate-partial-width-windows : comportement dans un tampon
;;   n'occupant qu'une fraction de la largeur de la fenêtre (par
;;   exemple, après un découpage horizontal C-x 3).
(setq truncate-lines nil)
(setq truncate-partial-width-windows nil)


;; Lorsqu'on lance Emacs, crée un nouveau tampon (vide) ou ouvre un
;; fichier dont Emacs n'arrive pas à déterminer le type, il bascule
;; par défaut dans le mode fondamental « lisp-interaction-mode ». Ce
;; choix n'est pas pertinent (pour moi du moins) et je préfère qu'il
;; opte dans ce cas pour le mode texte.
;; Au lancement d'Emacs :
(setq initial-major-mode 'text-mode)
;; A la création d'un tampon ou l'ouverture d'un fichier de type non
;; reconnu :
(setq default-major-mode 'text-mode)


;; Faire apparaître la position du curseur dans la ligne modale
(setq column-number-mode t)
(setq line-number-mode t)


;; Afficher l'heure dans la barre d'état (format 24 heures)
(display-time)
(setq display-time-24hr-format t)


;; Curseur clignotant
(blink-cursor-mode t)


;; Selon les règles typographiques françaises, le point final d'une
;; phrase n'est suivi que d'un seul espace (contre deux dans la
;; tradition anglo-saxonne). Il est utile qu'Emacs le sache pour
;; formater correctement les textes.
(setq sentence-end-double-space nil)


;; On peut insérer un caractère « spécial » ne correspondant à aucune
;; touche du clavier en tapant la séquence « C-q <code ascii> RET ».
;; Par défaut, Emacs attend la valeur octale du code ASCII mais je
;; connais mieux les valeurs décimales. Autant qu'Emacs s'adapte...
(setq read-quoted-char-radix 10)


;; Configuration spécifique à une utilisation sous X-Window
(if window-system
    (progn
      ;; Taille par défaut de la fenêtre 100 x 60 caractères.
      ;; Pour ajouter un positionnement (en pixels), il faut saisir la
      ;; ligne suivante :
      ;; (setq initial-frame-alist
      ;;       '((top . 1) (left . 1) (width . 100) (height . 60)))
      (setq initial-frame-alist '((width . 100) (height . 60)))

      ;; Personnalisation du curseur
      (setq default-cursor-type '(bar . 2))
      (set-cursor-color "red")

      ;; Suppression de la barre d'icônes
      (tool-bar-mode 0)
      ; (menu-bar-mode 0)

      ;; Taille de la police employée sous X
      (set-default-font "-*-fixed-medium-r-*-*-*-130-*-*-*-*-iso10646-*")
    )
)


;; Inhiber l'affichage du message d'accueil
(setq inhibit-startup-message t)


;; C'est fastidieux de taper « yes » pour confirmer, raccourcissons
;; cela à « y » (idem pour « no », désormais « n »).
(fset 'yes-or-no-p 'y-or-n-p)


;; Supprimer les fichiers de sauvegarde en quittant.
;; (vous savez, ces fameux fichiers dont le nom se termine par « ~ »)
(setq make-backup-files nil)


;; Configuration des paramètres d'impression Postscript
(require 'ps-print)
(setq ps-paper-type 'a4
      ps-font-family 'Courier
      ps-print-size 10
      ps-print-header t
      ps-landscape-mode nil)
(setq-default ps-header-lines 1)
(setq ps-print-color-p 'black-white)


;; Sauvegarde des historiques (fichiers ouverts, fonctions invoquées,
;; expressions rationnelles saisies, etc.) d'une session à l'autre.
(require 'session)
(add-hook 'after-init-hook 'session-initialize)
(setq session-initialize '(de-saveplace session places keys menus))


;; La flèche de direction vers le bas ne doit pas étendre le fichier
;; en fin de tampon (seul un retour chariot explicite le fait).
(setq next-line-add-newlines nil)


;; Laisser le curseur en place lors d'un défilement par pages. Par
;; défaut, Emacs place le curseur en début ou fin d'écran selon le
;; sens du défilement.
(setq scroll-preserve-screen-position t)


;; Si cette variable est différente de 'nil', lorsque l'on est à la
;; fin d'une ligne, le déplacement vertical du curseur s'accompagne
;; d'un déplacement horizontal pour atteindre la fin de la ligne
;; courante. Si cette variable vaut 'nil', le déplacement est
;; strictement vertical.
(setq track-eol nil)


;; Colorisation syntaxique maximale dans tous les modes
(require 'font-lock)
(global-font-lock-mode t)
(setq font-lock-maximum-decoration t)


;; Montrer la correspondance des parenthèses (systématiquement et non
;; seulement après la frappe)
(require 'paren)
(show-paren-mode t)
(setq blink-matching-paren t)
(setq blink-matching-paren-on-screen t)
(setq show-paren-style 'expression)
(setq blink-matching-paren-dont-ignore-comments t)


;; Mise en surbrillance de la zone sélectionnée
(transient-mark-mode 1)


;; Lorsqu'on saisit un texte alors qu'une zone est sélectionnée, cette
;; dernière est écrasée par le texte saisi.
(delete-selection-mode 1)


;; Ne pas remplacer les espaces par des tabulations
(setq-default indent-tabs-mode nil)


;; Fonction remplaçant toutes les tabulations du tampon courant par le
;; nombre d'espaces qui ne modifie pas la mise en page apparente
;; (étrangement, la fonction native d'Emacs ne s'applique qu'à une
;; région, pas à un tampon entier).
(defun untabify-buffer ()
  "Untabify the entire buffer."
  (interactive)
  (untabify (point-min) (point-max))
)


;; Si le support des images est activé alors les afficher lorsqu'on
;; les ouvre.
(if (fboundp 'auto-image-file-mode)
  (auto-image-file-mode 1)
)


;; Chiffrement à la volée
(require 'mailcrypt-init)
(mc-setversion "gpg")
(setq mc-gpg-user-id "sebastien.dinot@free.fr")
(setq mc-passwd-timeout 600)


;; Lorsque le fichier est sauvegardé, demander s'il faut ajouter un
;; saut de ligne final lorsqu'il est absent et effacer les espaces
;; superflus en fin de ligne.
(setq require-final-newline 'query)
(add-hook 'write-file-hooks 'delete-trailing-whitespace)


;; Par défaut, lors du reformatage du texte (M-q), Emacs ne respecte
;; pas les règles typographiques françaises qui veulent qu'un signe de
;; ponctuation double soit placé sur la même ligne que le mot qui le
;; précède, malgré l'espace (fine) qui le sépare de ce mot. Les
;; déclarations suivantes corrigent le problème. Merci à Matthieu Moy
;; pour la précieuse astuce (http://www-verimag.imag.fr/~moy/emacs/).
(defun my-fill-nobreak-predicate ()
  (save-match-data
    (or (looking-at "[ \t]*[])}»!?;:]")
        (looking-at "[ \t]*\\.\\.\\.")
        (save-excursion
          (skip-chars-backward " \t")
          (backward-char 1)
          (looking-at "[([{«]")
        )
    )
  )
)
(setq fill-nobreak-predicate 'my-fill-nobreak-predicate)


;; Lorsque le curseur atteint la fin de la fenêtre, le contenu se
;; déplace d'une seule ligne et non d'une demi-fenêtre.
(setq scroll-step 1)


;; Conserver une seule ligne de contexte lors d'un déplacement d'une
;; page dans le contenu (appui sur « page up » ou « page down »)
(setq next-screen-context-lines 1)


;; L'outil de correction orthographique « ispell » doit utiliser le
;; thésaurus français.
(require 'ispell)
(setq ispell-dictionary "francais")


;; Nom français des jours et mois affichés dans le calendrier
;; (cf. M-x calendar)
(setq european-calendar-style t)
(setq calendar-week-start-day 1)
(defvar calendar-day-name-array
  ["dimanche" "lundi" "mardi" "mercredi" "jeudi" "vendredi" "samedi"])
(defvar calendar-day-abbrev-array
  ["dim" "lun" "mar" "mer" "jeu" "ven" "sam"])
(defvar calendar-month-name-array
  ["janvier" "février" "mars" "avril" "mai" "juin"
   "juillet" "août" "septembre" "octobre" "novembre" "décembre"])
(defvar calendar-month-abbrev-array
  ["jan" "fév" "mar" "avr" "mai" "jun"
   "jul" "aoû" "sep" "oct" "nov" "déc"])


;; Avant de sauvegarder un fichier, rechercher (par défaut, dans les 8
;; premières lignes) un marqueur d'horodate de modification et, s'il
;; existe, l'actualiser.
(add-hook 'write-file-hooks 'time-stamp)
;; Format de l'horodate insérée (syntaxe propre à Emacs).
(setq time-stamp-format "%:y-%02m-%02d %02H:%02M:%02S")
;; Motif à rechercher (avec, en préfixe et suivi d'un slash, le nombre
;; de lignes à scruter à partir du haut du fichier). A la réflexion,
;; je préfère conserver le motif par défaut car la normalisation a des
;; avantages. (c:
; (setq time-stamp-pattern "20/Modifié le %%$")


;; Insertion de date au format AAAA-MM-JJ
(defun insert-iso-date-string ()
  "Insert a nicely formated date string."
  (interactive)
  (insert (format-time-string "%Y-%m-%d")))
;; La séquence « C-c d » insère la date
(global-set-key [(control c) (d)] 'insert-iso-date-string)


;; Insertion de date en clair JJ Mois AAAA
(defun insert-text-date-string ()
  "Insert a nicely formated date string."
  (interactive)
  (insert (format-time-string "%d %B %Y")))
;; La séquence « C-c S-d » insère la date
(global-set-key [(control c) (shift d)] 'insert-text-date-string)


;; Insertion d'horodate au format AAAA-MM-JJ HH:NN:SS
(defun insert-iso-time-string ()
  "Insert a nicely formated timestamp string."
  (interactive)
  (insert (format-time-string "%Y-%m-%d %H:%M:%S")))
;; La séquence « C-c t » insère l'horodate
(global-set-key [(control c) (t)] 'insert-iso-time-string)


;; Insertion d'horodate au format AAAA-MM-JJ HH:NN:SS
(defun insert-text-time-string ()
  "Insert a nicely formated timestamp string."
  (interactive)
  (insert (format-time-string "%d %B %Y à %H:%M:%S")))
;; La séquence « C-c S-t » insère l'horodate
(global-set-key [(control c) (shift t)] 'insert-text-time-string)


;; Surcharge de la séquence « C-x k ». Au lieu de demander le nom du
;; tampon à détruire, elle détruit systématiquement le tampon courant.
(global-set-key [(control x) (k)] 'kill-this-buffer)


;; « F6 » <=> aller à la ligne précisée ensuite (alternative à la
;;            séquence « M-g g »)
(global-set-key [f6]  'goto-line)


;; F9       <=> remplacement interactif simple.
;; Shift-F9 <=> remplacement interactif intégrant des expressions
;;              régulières.
(global-set-key [f9]         'query-replace)
(global-set-key [(shift f9)] 'query-replace-regexp)


;; A partir de la version 21 d'Emacs, les séquences de touches
;; ci-dessous ont le comportement défini ici. Les déclarations qui
;; suivent sont donc inutiles mais je les garde tout de même sous le
;; coude pour le cas où...
;;
;; Suppr.      <=> Supprimer le caractère sous le curseur
;; Backspace   <=> Supprimer le caractère précédent le curseur
;; Home        <=> Début de ligne
;; End         <=> Fin de ligne
;; Ctrl + Home <=> Début du document
;; Ctrl + End  <=> Fin du document
;;
;; (global-set-key [delete] 'delete-char)
;; (global-set-key [backspace] 'delete-backward-char)
;; (global-set-key [home] 'beginning-of-line)
;; (global-set-key [end]  'end-of-line)
;; (global-set-key [(control home)] 'beginning-of-buffer)
;; (global-set-key [(control end)]  'end-of-buffer)


;; Effacement des caractères blancs (y compris les nouvelles lignes)
;; jusqu'au prochain caractère non blanc. Cette fonction est bien
;; utile après un copier-coller de puis Netscape.
(defun trim-whitespace () (interactive)
  "Effacer les caracteres blancs jusqu'au prochain non blanc"
  (save-excursion
    (if (re-search-forward "[  \t\r\n]*[^  \t\r\n]" nil t)
      (delete-region (match-beginning 0) (- (point) 1))
    )
  )
)
(global-set-key [f10] 'trim-whitespace)


;; F11        <=> Masquer le bloc de code courant
;; F12        <=> Montrer le bloc de code courant
;; Meta + F11 <=> Masquer tous les blocs de code
;; Meta + F12 <=> Montrer tous les blocs de code
(global-set-key [f11] 'hs-hide-block)
(global-set-key [f12] 'hs-show-block)
(global-set-key [(meta f11)] 'hs-hide-all)
;; FIXME: Pourquoi cette association ne fonctionne-t'elle pas alors
;; qu'invoquée explicitement, la commande « hs-show-all » fonctionne
;; parfaitement.
(global-set-key [(meta f12)] 'hs-show-all)


;; Changement rapide de tampon via les séquences « C-x C-left arrow »
;; et « C-x C-right arrow ». Cette fonctionnalité est nativement
;; implémentée à partir de la version 22 d'Emacs (le choix des
;; séquences de touches vient de là).
;;
;; Merci à Young-Il Choo <choo@cs.yale.edu> pour ces fonctions
;; indispensables.
(if (< emacs-major-version 22)
  (progn

    (defun yic-ignore (str)
      (or
        ;; Liste des tampons à ignorer systématiquement
        (string-match "\\*Buffer List\\*" str)
        (string-match "^TAGS" str)
        (string-match "^\\*Messages\\*$" str)
        (string-match "^\\*Completions\\*$" str)
        (string-match "^ " str)

        ;; Ignorer aussi les tampons déjà visibles dans une autre
        ;; trame de cette même instance d'Emacs.
        (memq str
          (mapcar
            (lambda (x)
              (buffer-name
                (window-buffer
                 (frame-selected-window x)
                )
              )
            )
            (visible-frame-list)
          )
        )
      )
    )

    ;; Sélection du tampon suivant dans la liste en tenant compte de
    ;; ceux qui doivent être ignorés.
    (defun yic-next (ls)
      "Déterminer le prochain tampon valide à afficher"
      (let* ((ptr ls)
              bf bn go
            )
        (while (and ptr (null go))
          (setq bf (car ptr)  bn (buffer-name bf))
          (if (null (yic-ignore bn))
            (setq go bf)
            (setq ptr (cdr ptr))
          )
        )
        (if go (switch-to-buffer go))
      )
    )

    ;; Affichage du tampon précédent dans la liste des tampons valides
    (defun yic-prev-buffer ()
      "Afficher le tampon suivant en ignorant ceux non souhaités"
      (interactive)
      (yic-next (reverse (buffer-list)))
    )

    ;; Affichage du tampon suivant dans la liste des tampons valides
    (defun yic-next-buffer ()
      "Afficher le tampon précédent en ignorant ceux non souhaités"
      (interactive)
      (bury-buffer (current-buffer))
      (yic-next (buffer-list))
    )

    (global-set-key [(control x) (control left)] 'yic-prev-buffer)
    (global-set-key [(control x) (control right)] 'yic-next-buffer)
  )
)


;; Effacer tous les espaces superflus en fin de ligne. A partir de la
;; version 21, Emacs implémente nativement cette fonctionnalité. Mais
;; je laisse ici cette implémentation commentée au cas où je tomberais
;; sur une version antédiluvienne d'Emacs.
;;
;; (defun delete-trailing-whitespace ()
;;   "Effacer les espaces et tabulations en fin de chaque ligne du tampon"
;;   (interactive)
;;   (progn
;;     (save-excursion
;;       (goto-line 1)
;;       ;; ATTENTION, dans la liste ci-dessous, il y a 3 espaces de
;;       ;; nature différente : normal, insécable, tabulation.
;;       (replace-regexp "[  \t]+$" "")
;;     )
;;   )
;; )


;; ===================================================================
;; =====   Interaction avec la souris                            =====
;; ===================================================================

;; Lors d'un « copier-coller » à la souris, insérer le texte au niveau
;; du point cliqué et non à la position du curseur texte.
(setq mouse-yank-at-point nil)


;; Prise en charge de la molette de la souris.
;; Utilisée seule, la rotation de la molette provoque un défilement de
;; 5 lignes par cran. Combinée à la touche Shift, le défilement est
;; réduit à une ligne. Combinée à la touche Control, le défilement
;; s'effectue page (1 hauteur de fenêtre) par page.
(require 'mwheel)
(mouse-wheel-mode 1)


;; Si le mode précédent n'est pas disponible, décommenter les lignes
;; qui suivent pour le remplacer.
;;
;; Molette seule <=> déplacement de cinq lignes
;; (defun up-slightly () (interactive) (scroll-up 5))
;; (defun down-slightly () (interactive) (scroll-down 5))
;; (global-set-key [mouse-4] 'down-slightly)
;; (global-set-key [mouse-5] 'up-slightly)
;;
;; Molette + Shift <=> déplacement d'une ligne
;; (defun up-one () (interactive) (scroll-up 1))
;; (defun down-one () (interactive) (scroll-down 1))
;; (global-set-key [S-mouse-4] 'down-one)
;; (global-set-key [S-mouse-5] 'up-one)
;;
;; Molette + Control <=> déplacement d'une page
;; (defun up-a-lot () (interactive) (scroll-up))
;; (defun down-a-lot () (interactive) (scroll-down))
;; (global-set-key [C-mouse-4] 'down-a-lot)
;; (global-set-key [C-mouse-5] 'up-a-lot)


;; ===================================================================
;; =====   Edition de code C/C++                                 =====
;; ===================================================================

;; Charger le mode C/C++
(require 'cc-mode)


;; Définition d'un style (i.e. une mise en page) conforme à mes petites
;; habitudes. La signification des différents paramètres est expliquée
;; dans le manuel du mode CC, notamment pour les indentations la page :
;; http://www.delorie.com/gnu/docs/emacs/cc-mode_32.html
(defconst my-c-style
  '(;; L'appui sur la touche « tabulation » ne doit pas insérer une
    ;; tabulation mais indenter la ligne courante en fonction du
    ;; contexte et des règles définies dans le style.
    (c-tab-always-indent . t)
    ;; Formatage à 78 colonnes
    (fill-column . 78)
    ;; L'indentation se fait avec un pas de 2 caractères
    (c-basic-offset . 2)
    ;; Les commentaires qui occupent seuls une ligne sont alignés avec
    ;; le code
    (c-comment-only-line-offset . 0)
    ;; Les commentaires multi-ligne commencent par une simple ligne '/*'
    (c-hanging-comment-starter-p . t)
    ;; et se terminent par une simple ligne '*/'
    (c-hanging-comment-ender-p . t)
    ;; Cas où une accolade est « électrique » (i.e. provoque une mise
    ;; en page automatique)
    (c-hanging-braces-alist .
      ((substatement-open after)
       (brace-list-open)
       (brace-entry-open)
       (block-close . c-snug-do-while)
       (extern-lang-open after)
       (inexpr-class-open after)
       (inexpr-class-close before)))
    ;; Cas où le caractère « : » est « électrique » (i.e. provoque une
    ;; mise en page automatique)
    (c-hanging-colons-alist .
      ((member-init-intro before)
       (inher-intro)
       (case-label after)
       (label after)
       (access-label after)))
    ;; Nettoyage automatique de certaines mises en page
    (c-cleanup-list .
      (scope-operator
       empty-defun-braces
       defun-close-semi))
    (c-offsets-alist .
      (;; Première ligne d'une construction de premier niveau (par
       ;; exemple une déclaration de fonction)
       (topmost-intro . 0)
       ;; Lignes suivantes d'une construction de premier niveau
       (topmost-intro-cont . 0)
       ;; Première ligne d'une liste d'argument
       (arglist-intro . +)
       ;; Argument lorsque la ligne ouvrant la liste ne contient pas
       ;; d'argument.
       (arglist-cont . 0)
       ;; Argument lorsque la ligne ouvrant la liste en contient au moins un.
       (arglist-cont-nonempty . c-lineup-arglist)
       ;; Parenthèse fermant une liste d'arguments mais non précédée d'un
       ;; argument sur la même ligne.
       (arglist-close . c-lineup-close-paren)
       ;; Première ligne d'une instruction quelconque
       (statement . 0)
       ;; Lignes suivantes de l'instruction quelconque
       (statement-cont . +)
       ;; Première ligne d'un bloc
       (statement-block-intro . +)
       ;; Première ligne d'un bloc case
       (statement-case-intro . +)
       ;; Première ligne d'un bloc case commençant par une accolade
       (statement-case-open . 0)
       ;; Instruction suivant une instruction de test ou de contrôle de boucle
       (substatement . +)
       ;; Accolade suivant une instruction de test ou de contrôle de boucle
       (substatement-open . 0)
       ;; Accolade ouvrante d'une énumération ou d'un tableau statique
       (brace-list-open . 0)
       ;; Accolade fermante d'une énumération ou d'un tableau statique
       (brace-list-close . 0)
       ;; Première ligne d'une énumération ou d'un tableau statique
       (brace-list-intro . +)
       ;; Lignes suivantes d'une énumération ou d'un tableau statique
       (brace-list-entry . 0)
       ;; Lignes suivantes d'une énumération ou d'un tableau statique
       ;; commençant par une accolade ouvrante
       (brace-entry-open . 0)
       ;; Label d'un switch
       (case-label . +)
       ;; Label d'une classe (public, protected, private) en retrait d'un pas
       ;; par rapport à l'indentation normale au sein d'une classe (cf.
       ;; déclaration « inclass » plus bas).
       (access-label . -)
       ;; Autres labels
       (label . 0)
       ;; Ouverture de bloc
       (block-open . 0)
       ;; Fermeture de bloc
       (block-close . 0)
       ;; A l'intérieur d'une chaîne multi-ligne
       (string . c-lineup-dont-change)
       ;; Première ligne d'un commentaire
       (comment-intro . c-lineup-comment)
       ;; A l'intérieur d'un commentaire C multi-ligne
       (c . c-lineup-C-comments)
       ;; Accolade ouvrant une fonction
       (defun-open . 0)
       ;; Accolade fermant une fonction
       (defun-close . 0)
       ;; Code suivant l'accolade ouvrante d'une fonction
       (defun-block-intro . +)
       ;; Clause else d'une expression conditionnelle
       (else-clause . 0)
       ;; Clause catch d'une instruction try
       (catch-clause . 0)
       ;; Accolade ouvrant une déclaration de classe
       (class-open . 0)
       ;; Accolade fermant la déclaration de classe
       (class-close . 0)
       ;; Accolade ouvrante d'une méthode définie dans la classe elle-même
       ;; (inline)
       (inline-open . 0)
       ;; Accolade fermante de la méthode inline
       (inline-close . 0)
       ;; Alignement des opérateurs de flux (<< et >>) sur les opérateurs de
       ;; flux de la ligne précédente
       (stream-op . c-lineup-streamop)
       ;; Ligne incluse dans une déclaration de classe (double indentation car
       ;; les labels d'accès public, protected et private sont déjà indentés)
       (inclass . ++)
       ;; Accolade ouvrant un bloc en langage externe (extern "C" {})
       (extern-lang-open . 0)
       ;; Accolade fermant un bloc en langage externe
       (extern-lang-close . 0)
       ;; Indentation dans un bloc de langage externe
       (inextern-lang . +)
       ;; Accolade ouvrant un bloc d'espace de nom
       (namespace-open . 0)
       ;; Accolade fermant un bloc d'espace de nom
       (namespace-close . 0)
       ;; Indentation dans un bloc d'espace de nom
       (innamespace . +)
       ;; Première ligne d'héritage
       (inher-intro . +)
       ;; Lignes suivantes d'héritage
       (inher-cont . c-lineup-multi-inher)
       ;; Première ligne de la liste d'initialisation
       (member-init-intro . +)
       ;; Lignes suivantes de la liste d'initialisation
       (member-init-cont . c-lineup-multi-inher)
       ;; Lignes entre la déclaration de fonction et l'accolade ouvrante. En
       ;; C, il n'y a rien mais en C++, il y a les listes d'initialisation
       (func-decl-cont . +)
       ;; Première ligne d'une macro (avec un décalage négatif excessif afin
       ;; d'être certain qu'elle reste collée à gauche en toute circonstance
       (cpp-macro . -1000)
       ;; Lignes suivantes d'une macro
       (cpp-macro-cont . c-lineup-dont-change)
       ;; Fonction amie
       (friend . 0)
       ;; while qui termine une instruction do { ... } while (...);
       (do-while-closure . 0)
       ;; Bloc d'instruction à l'intérieur d'une expression
       (inexpr-statement . 0)
       ;; Définition de classe à l'intérieur d'une expression (cela n'a de
       ;; sens qu'en Java mais autant définir ce contexte au cas où...)
       (inexpr-class . +)
       ;; Lignes autres que la première d'un modèle de fonction ou de classe
       (template-args-cont . +)
       ;; Arguments d'une fonction à la sauce K&R
       (knr-argdecl-intro . +)
       (knr-argdecl . 0)))
    (c-echo-syntactic-information-p . t)
  )
  "My C Programming Style"
)


;; Faire du style défini ci-dessus le style C/C++ par défaut
(defun my-c-mode-common-hook ()
  (c-add-style "PERSONAL" my-c-style t)
)
(add-hook 'c-mode-hook 'my-c-mode-common-hook)
(add-hook 'c++-mode-hook 'my-c-mode-common-hook)


; Activation systématique du mode mineur HS dans les modes C/C++
(add-hook 'c-mode-common-hook 'hs-minor-mode t)


;; Le module ctypes permet d'ajouter à la liste des types de données
;; C/C++ des types non reconnus par défaut. Ces types sont alors
;; connus et gérés par le module de colorisation syntaxique.
(require 'ctypes)


;; Chargement du fichier décrivant les types C/C++ non reconnus par
;; défaut (~/elisp/ctypes).
(defun my-ctypes-load-hook ()
  (ctypes-read-file "~/elisp/ctypes" nil t t)
)
(add-hook 'ctypes-load-hook 'my-ctypes-load-hook)


;; ===================================================================
;; =====   Edition de code Perl                                  =====
;; ===================================================================

;; Charger le mode Perl (cperl-mode est un perl-mode amélioré).
(require 'cperl-mode)


;; On définit perl-mode comme un alias de cperl-mode pour ne pas avoir
;; à altérer les déclarations par défaut.
(defalias 'perl-mode 'cperl-mode)


;; Adaptation de l'indentation du module cperl-mode à mes goûts.
(add-hook 'cperl-mode-hook 'my-cperl-mode-hook t)
(defun my-cperl-mode-hook ()
  (setq cperl-indent-level 2)
  (setq cperl-continued-statement-offset 0)
  (setq cperl-extra-newline-before-brace t)
)


;; ===================================================================
;; =====   Edition de code XML                                   =====
;; ===================================================================

(require 'nxml-mode)
(add-hook 'nxml-mode-hook
          (lambda ()
            (setq fill-column 78)
          )
)

(fset 'xml-mode 'nxml-mode)


;; ===================================================================
;; =====   Mode d'édition préféré par type de fichier            =====
;; ===================================================================

; Sélection du mode d'édition en fonction du motif satisfait par le
; nom du fichier.
(setq auto-mode-alist
  (append
    '(("\\.sh\\'" . sh-mode)
      ("bash" . sh-mode)
      ("profile" . sh-mode)
      ("Makefile\\'" . makefile-mode)
      ("makefile\\'" . makefile-mode)
      ("\\.mk\\'" . makefile-mode)
      ("\\.c\\'"  . c-mode)
      ("\\.h\\'"  . c-mode)
      ("\\.cc\\'" . c++-mode)
      ("\\.hh\\'" . c++-mode)
      ("\\.cpp\\'"  . c++-mode)
      ("\\.hpp\\'"  . c++-mode)
      ("\\.pgc\\'"  . c++-mode) ; Fichiers « Embedded PostgreSQL in C »
      ("\\.p[lm]\\'" . cperl-mode)
      ("\\.el\\'" . emacs-lisp-mode)
      ("\\.emacs\\'" . emacs-lisp-mode)
      ("\\.l\\'" . lisp-mode)
      ("\\.lisp\\'" . lisp-mode)
      ("\\.txt\\'" . text-mode)
      ("\\.sgml\\'" . nxml-mode)
      ("\\.xml\\'" . nxml-mode)
      ("\\.xsl\\'" . nxml-mode)
      ("\\.svg\\'" . nxml-mode)
      ("\\.[sx]?html?\\'" . nxml-mode)
      ("\\.tpl\\'" . nxml-mode)
      ("\\.php\\'" . php-mode)
      ("\\.inc\\'" . php-mode)
      ("\\.awk\\'" . awk-mode)
      ("\\.tex\\'" . latex-mode)
     )
     auto-mode-alist
  )
)