Emacs, une petite introduction

Table des matières

1 Introduction

1.1 Emacs ?

Emacs est sans doute aucun l'éditeur de texte le plus polyvalent qui existe, au point qu'il en est un peu effrayant. Ce ne sont pas seulement des tonnes de contrôles clavier et commandes à apprendre, mais des greffons qui en changent ses fonctionnalités (minor modes) ou qui l'altèrent totalement (major modes). Comme vous avez l'opportunité de le décrouvrir dès le début de votre formation dans le supérieur, vous disposez réellement d'un temps suffisant pour en faire un outil qui vous permettra un gain de productivité notable, et d'un confort assez inégalé (ce confort n’apparaît pas dans les premiers contacts…).

Vous avez appris les fonctionnalités de base d'Emacs (le tutoriel intégré que vous devez maintenant connaître par coeur), et maintenant des chemins s'ouvrent dans toutes les directions. Ce cours commencera par compléter le tutoriel de quelques fonctionnalités de base d'Emacs, vous montrera comment construire votre fichier de configuration puis abordera principalement deux thématiques:

  • orgmode qui est un des points forts d'emacs
  • le fichier de configuration d'emacs, qui créera également l'opportunité de découvrir de nombreux outils pour le développement

Ce qui est écrit ici ne fera qu'effleurer différentes possibilités offertes par emacs, et a principalement pour vocation à vous donner envie de creuser et de vous approprier ce logiciel dont la versatilité est impressionnante.

emacs_vi_nano.jpg

Figure 1 : Les différents éditeurs

La communication d'emacs vers le navigateur est parfaite, la réciproque est inexistante. De plus, il manque à emacs un visualiseur html de qualité. Il existe des commandes pour afficher des pages web dans emacs, mais leur rendu n'est pour l'instant pas satisfaisant, ce qui impose de travailler en ayant conjointement un navigateur ouvert. J'ai l'espoir que dans une future version ce point soit corrigé, ce qui permettra à emacs de devenir plus encore que maintenant une interface universelle.

1.2 Pré-requis

Avoir suivi une dizaine de fois le tutoriel d'emacs1 intégré au logiciel (accessible soit au démarrage d'Emacs, soit dans le menu d'aide).

Savoir installer une application sous Linux.

1.3 Lancer Emacs

La façon standard de démarrer Emacs est emacs & disown emacs (lance emacs en tâche de fond, et le 'détache' du terminal afin que si on ferme le terminal, cela ne ferme pas également emacs), mais il existe quelques options qui sont assez fréquemment utilisées :

  • --debug-init lance le mode débuggage au démarrage pour le chargement des fichiers de configuration, vous allez l'utiliser je pense :),
  • -nw no window, emacs s'ouvre en mode texte, à l'intérieur du shell, pour ceux qui n'aiment pas les interfaces graphiques, se combine souvent avec l'option qui suit,
  • -Q démarrer avec une configuration minimale (ne pas charger les fichiers de configuration, l'écran de démarrage, …). Comme le chargement d'un emacs avec de nombreux greffons peut prendre plus d'une minute, cette option peut être utile pour :
    • éditer un fichier vite fait, on peut par exemple définir emacs -nw -Q comme éditeur par défaut pour ouvrir un fichier texte avec une interface graphique,
    • récupérer emacs après avoir rendu hors d'usage les fichiers de configuration (malheureusement cela arrive plus souvent qu'on ne le désire),
  • NB : il existe une autre façon d'obtenir un démarrage d'emacs 'instantané' et cette fois totalement configuré : utiliser une option d'emacs qui le définit comme un serveur. On peut faire tourner ce serveur en tant que daemon ou simplement avoir la première instance d'emacs qui jouera le rôle de serveur, les instances suivantes, lancées par emacsclient ne chargeront en réalité pas le logiciel, mais se comporteront plutôt comme des buffers extériorisés.

1.4 Saveurs emacs

Emacs admet quelques saveurs différentes, il existe Xemacs qui est une réelle bifurcation d'emacs (il y a des différences techniques et politiques), ou simplement des modificateurs qui changent l'apparence ou le comportement d'emacs (les deux grands 'mod' en ce moment sont spacemacs et doom emacs qui me semblent très intéressants, même si je ne les utilise pas).

2 Nouvelles commandes

real_programmers.png

Figure 2 : Les vrais programmeurs

2.1 Balises pour se déplacer

Il est fréquemment utile de se déplacer à un autre point d'un fichier, puis de replacer le curseur là où il était précédemment. Il existe pour cela différentes méthodes. Mise à part la première (plus une bidouille qu'une vraie méthode), les autres méthodes sont à bien maîtriser (c'est la méthode 4 qui va commencer à faire ressembler emacs à un IDE). Une fois la configuration terminée, on disposera également de nouvelles façons de naviguer (qui ne se substitueront pas à celles-ci).

  1. Utiliser la marque : lorsque du texte est sélectionné, on peut par C-x C-x faire passer le curseur d'une extrémité à l'autre de la sélection. Ainsi, on peut fixer la marque C-SPC, se déplacer, et revenir là où on a fixé la marque.
  2. Les registres, on peut en fixer autant qu'il y a de lettres. On place le curseur en un point du document, C-x r SPC letter, et lorsqu'on désire revenir à cette position C-x r j same_letter. Attention : les registres ne sont pas sauvegardés lorsqu’on quitte emacs !
  3. Les bookmarks fonctionnent de façon similaire aux registres, mais ils sont conservés sur le long terme et réutilisables aux prochaines utilisations du fichier.
    • Pour créer un bookmark C-x r m, et il sera demandé un nom.
    • Pour aller à un bookmark C-x r b, puis son nom.
    • Pour lister les bookmarks C-x r l, dans cet écran, on a accès à de nombreuses commandes (renommage, effacement, …), l'aide étant accessible par la commande usuelle C-h
  4. Pour le code, le système de 'tags' de linux est utilisable. Ils proviennent de 'ctags' qu'il faut installer en ligne de commande. Ils permettent un nommage automatique des points de référence du code. Actuellement c'est xref qui est chargé de leur gestion sous emacs.
    • Il est possible de créer des tags de façon automatique (c'est un des points qui les différentie des bookmarks) par la commande shell ctags -R -e * (ou par les menus) : depuis le répertoire de base du projet, les fichiers du répertoire et des sous répertoire vont être parcourus ; (l'option -e est pour emacs), ou en exécutant des fonction de etags (par défaut dans emacs) ou exhuberantCtags (n'est pas présent par défaut, à ajouter). Ces tags automfatiques vont repérer les points de nommages de votre code (fonctions, classes, structures,…). Il sera par la suite possible de naviguer grâce à ces tags.
    • Pour l’utilisation
      • M-. déplacer le curseur sur le point de référence du tag (s'il y en a plusieurs, il sera possible de naviguer dans les propositions)
      • M-, revenir au point de départ
      • M-? rechercher toutes les occurrences d'un identificateur
      • C-M-. rechercher à l'aide d'une expression régulière

2.2 Longueur lignes

Il est pratique de définir la largeur de la page sur laquelle travailler. La commande C-x f permer de la définir. La valeur proposée par défaut est la position actuelle du curseur. Pour comprendre son effet :

  • définir une largeur de 10
  • tapper une certaine quantité de texte, de longs paragraphes
  • se placer dans un paragraphe déjà tappé, et M-q, le paragraphe s'adapte à la taille demandée
  • définir la largeur à 5, M-q et le paragraphe diminue

Personnellement je travaille en général avec une largeur de 90 qui est supérieure au standard (80 colonnes qui nous vient des machines à écrire et des premiers terminaux, et toujours défendue par de nombreux programmeurs). Vous pouvez activer le retour à la ligne automatique avec la commande M-x auto-fill-mode qui active/désactive la fonction.

2.3 Les macros 'clavier'

Emacs permet d'enregistrer une suite de commandes afin de pouvoir la ré-exécuter ultérieurement. On va s'intéresser ici aux macros sans paramètres, qui ne sont que des suites de frappes au clavier.

  • Pour débuter l'enregistrement d'une macro : F3
  • Pour terminer l'enregistrement d'une macro : F4
  • Pour exécuter la dernière macro enregistré : F4

2.3.1 Exemple d'utilisation

  1. Placer le curseur dans un texte au milieu d'une ligne (il doit rester une dizaine de lignes après celle où il se trouve)
  2. Démarrer l'enregistrement d'une macro (F3)
  3. Se placer en début de ligne (C-a)
  4. Tapper 3 étoiles et un espace (***)
  5. Se placer en fin de ligne (C-e)
  6. Tapper un espace suivi de 3 étoiles (***)
  7. Descendre d'une ligne (C-n)
  8. Terminer l'enregistrement de la macro (F4)
  9. Appliquer le même traitement pour les 5 lignes qui suivent (C-u 5 F4)

2.3.2 Améliorer et conserver ses meilleures macros

La combinaison C-x C-k e suivie du nom de la macro (ou RET si on c'est la dernière macro créée) permet d'accéder, et éditer la macro. Plus précisément on peut :

  • nommer la macro (remplacer le texte 'last-kbd-macro')
  • affecter une séquence de touches afin de pouvoir l'exécuter directement en remplissant le champ key, par exemple C-x M-a (pas trop compliqué non plus, personnellement je trouve que les majuscules nécessitent des ascendants poulpes…)

emacs_octopus.jpg

Figure 3 : Ascendant poulpe : nécessaire pour boire son café en travaillant

Pour sauvegarder votre macro :

  1. Dans votre répertoire .emacs.d, si ce n'est déjà fait, créer un fichier mes_macros.el.
  2. Ouvrir ce fichier, placer le curseur à l'endroit où on désire ranger la nouvelle macro et M-x insert-kbd-macro <RET> nom_macro <RET>. La magie opère et on voit apparaitre un code en emacs-lisp qui réalise le même travail. [Par exemple (fset 'macro1 "\C-a** \C-e **\C-n") ].
  3. Affecter une combinaison de touche qui sera sauvegardée par (global-set-key "Séquence_de_touches" 'nom_de_la_macro). [Par exemple : (global-set-key "\C-\M-y" 'macro1) ].
  4. Mettre tous les commentaire nécessaires, le symbole pour les commentaires est ;; et le commentaire s'étend jusqu'à la fin de la ligne.
  5. Sauvegarder… et pour recharger ce fichier de macros : M-x load-file RET suivi de /.emacs.d/mes_macros.el.
  6. Ajouter la ligne (load-file "~/.emacs.d/mes_macros.el") au fichier ~/.emacs.d/init.el.

2.3.3 Les challenges

Il existe un site pour les défis sous vi : vimgolf. Le but est de réaliser une manipulation de texte en utilisant un minimum de frappes du clavier. Quoique anecdotique, c'est une façon amusante d'apprendre à bien manipuler les macros que de se frotter à ces challenges qui sont engénéral également bien adaptés à emacs.

Pour emacs, le plus simple est d'installer le package vimgolf et de se détendre de temps en temps en résolvant un des défis.

2.3.4 Pour aller plus loin, mais sans que cela se corse trop…

  • Astuces
    1. Pour exécuter un code e-lisp (Emacs lisp), il suffit de se mettre à la fin de sa dernière parenthèse fermante et C-x C-e. Par exemple, en plein milieu de n'importe quoi, on peut exécuter (* 5 (+ 1 3)) C-x C-e et voir s'afficher le résultat de l'évaluation en bas de l'écran (mini-buffer) ou (previous-line 5) C-x C-e et voir le curseur remonter de 5 lignes : dans emacs, tapper une touche, c'est exécuter une commande, par exemple taper a c'est exécuter la commande qui affiche 'a'.
    2. On peut regarder le code équivalent à un appel par un contrôle clavier. C-h k suivi par exemple de C-x 5 2, vous informe qu'on peut obtenir le même résultat que C-x 5 2 par le programme e-lisp : (make-frame-command)
    3. On peut accéder aux dernières commandes utilisées par M-x view-lossage
  • Pour une première approche d'e-lisp https://learnxinyminutes.com/docs/fr-fr/elisp-fr/ n'est pas rébarbatif.

    lisp_wizard.jpg

    Figure 4 : La programmation fonctionnelle

2.4 Sélections rectangulaires

https://www.gnu.org/software/emacs/manual/html_node/emacs/Rectangles.html

Les sélections rectangulaires permettent, comme leur nom l'indique de travailler à l'intérieur d'un rectangle que l'on a préalablement défini. On peut par exemple les utiliser pour travailler sur les colonnes d'un tableau, pour réaliser des mises en forme, du remplissage, …

Les commandes les plus utilisées commencent toutes par C-x r, à l'exclusion C-x SPC (qui permet de passer le mode sélection en mode rectangle).

2.4.1 Exemple d'utilisation : mettre des commentaires

  • Placer votre curseur au début de la première ligne de la zone à commenter
  • Marquer le début C-x SPC de la sélection (au lieu du C-SPC pour une sélection normale)
  • Placer le curseur au début de la dernière ligne à commenter
  • Se placer en mode écriture C-c r t
  • Tapper un texte (par exemple // si on pense à des commentaires en c, mais cela pourrait être n'importe quel texte –> le texte se place au début de chacun des lignes de la sélection

2.4.2 Exemple d'utilisation : effacer ce que l'on vient d'écrire

  • Placer votre curseur au début de la première ligne de la zone à commenter
  • Marquer le début C-x SPC de la sélection rectangulaire
  • Placer le curseur sur la dernière ligne de la zone de travail, juste après le dernier caractère à supprimer
  • Effacer C-d

2.4.3 Exemple d'utilisation : insérer/déplacer une colonne dans un tableau en markdown

  • Créer un tableau de quelques lignes en markdown (on reste sous emacs !!!), le tableau doit être propre (les colonnes font la bonne largeur)
  • Créer une nouvelle colonne en dessous
  • La sélectionner et la copier (ne pas oublier de se placer en mode sélection rectangulaire) C-x r M-w (rectangle, copier) ou la couper C-x r k (rectangle, kill)
  • Placer le curseur au début de la zone où vous voulez insérer la colonne
  • Coller la colonne C-x r y (rectangle, yank)

3 Org : introduction

org_licorne.jpg

Figure 5 : J'aime les licornes !

3.1 Présentation

Pour certains utilisateur, c'est LE greffon qui à lui seul justifie l'utilisation d'emacs… au point que sur la version actuelle d'emacs, ce n'est plus un greffon, mais une fonctionnalité intégrée. Comme vous allez l'apprendre, il permet de réaliser ce que fait le markdown, mais en allant plus loin, et en produisant des pages plus élégantes (le document que vous lisez actuellement est réalisé en orgmode)… Mais ce n'est pas seulement un langage pour la mise en forme de documents, aussi surprenant que cela paraisse, il est également conçu comme un système de gestion de tickets individuel (choses à faire, à quelle date, …, avec la possibilité de gérer un emploi du temps), il permet également de mélanger du code et du document (un fragment de code produit des données pour le graphique généré plus loin, etc…) à la façon d'un Jupyter Notebook.

Jupyter_logo.jpg

Figure 6 : Jupyter, un outil moins polyvalent mais tout de même très pratique

3.2 Documentation

On dispose plusieurs documents assez agréables en français auxquels vous pouvez vous référer (au début, surtout la version abrégée du manuel, et la 'cheat sheet') :

3.3 Créer un fichier org

La première possibilité consiste à nommer votre fichier avec l'extension .org, et la seconde à invoquer le mode org par M-x org-mode

3.4 Navigation à l'intérieur d'un fichier org

Lire préalablement la partie traitant de org et markdown.

Commencer par créer un texte contenant des titres, sous-titre, listes.

  • Pour créer un élement de même niveau (un nouveau titre, nouvel élément numéroté,…) M-ENT [astuce : si au milieu d'une liste vous insérez un bloc detexte, de code,… , penser à le décaler sur la droite, sinon la liste recommencera à 1 après le bloc]
    • Pour changer le niveau hiérarchique d'un élément, plus haut M-LEFT, plus bas M-RIGHT
    • Pour déplacer un élément vers le haut M-UP, vers le bas M-DOWN
    • Pour développer ou réduire une partie, sur le 'chapeau' de la partie (titre, …) C-TAB, la quantité de développement dépend du nombre de fois où ce contrôle est effectué.
    • Pour déplacer le curseur
      • au prochain élément C-c C-n
      • à l'élément précédent C-c C-p
      • au prochain élément de même niveau C-c C-f
      • à l'élément précédent de même niveau C-c C-b
    • Restreindre le buffer à une partie du fichier
      • Réduire le buffer au sous arbre actuel C-x n s (narrow subtree)
      • Réduire le buffer au bloc actuel C-x n b (narrow block)
      • Ré-afficher le buffer complet C-x n w (narrow widen)

3.5 Navigation 2 : les tags

Les tags permettent de rapidement filtrer un document, ou de rechercher certains éléments. Ce sont des clefs de rangement et peuvent être utiles de multiples façons. La lecture de Sacha Chua peut donner quelques pistes d’utilisation, ainsi qu'un petit tutoriel.

  • Un tag se place en fin de ligne d'un titre.
  • Il a pour format :NomTag:.
  • Le menu d'insertion de tag est accessible par C-c C-c
  • En début de fichier on peut ajouter une liste de tags par #+TAGS: URGENT(u) @FAMILLE(f) @COURSES(c) ce qui permettra par C-c C-c lettre d'insérer rapidement un tag.
  • Noter que les tags sont hérités : si une partie possède un certain tag, alors ces sous-parties le possèdent également.
  • Pour filtrer les parties de l'arbre qui contiennent certains tags C-c \
  • Si certains tags reviennent dans beaucoup de fichiers org, on peut les placer à l'intérieur du fichier de config afin qu'ils soient utilisable directement, par exemple :

    (setq org-agenda-custom-commands
          '(("u" todo "URGENT" nil) 
            ("f" todo "FAMILLE" nil)
            ("c" todo "COURSES" nil)             
            ("s" tags "URGENT-FAMILLE" nil)      ;; tag combiné : urgent, mais pas de la famille
            ("t" tags "URGENT&COURSES" nil)      ;; tag combiné : courses urgentes ...
            ))
    

3.6 Export du fichier

Une des forces d'orgmode est la possibilité d'exporter les fichiers en différents formats. Contrairement à ce que fait pandoc, ce n'est pas une traduction (pandoc peut être utilisé lorsqu'il n'y a pas d'autre solution plus spécialisée), mais plutôt une nouvelle interprétation du fichier.

Ainsi, le document que vous lisez actuellement est un export en html d'un document en orgmode (avec un fichier de configuration qui me plaît).

Il existe des greffons qui permettent d'exporter en différents formats classiques parmi lesquels :

  • markdown
  • beamer (slides en \(\LaTeX\))
  • iCalendar (permet de transférer ou aller chercher des agendas dans à peu près tout système d'agenda :google, ent, zimbra, …)
  • html
  • reveal (un type de slide assez moderne), visualisables par un navigateur
  • \(\LaTeX\)
  • odt (openoffice)
  • man (pages de manuel sous linux)
  • et quelques autres…

Pour exporter un fichier la combinaison de base est C-c C-e, ce qui fait apparaître un buffer qui indique les possibilités et les touches nécessaires afin d'obtenir le résultat désiré. Ces combinaison sont : une première touche pour choisir le style (html, latex, …) et une deuxième pour préciser si on veut afficher, sauvegarder, etc…

Il est à noter que ces exports, non configurés, ne sont pas nécessairement les plus beaux qui soient. Pour obtenir un résultat graphiquement intéressant, il est en général nécessaire de les paramétrer (ne pas hésiter à aller sur le net dénicher des paramètres qui donnent un rendu satisfaisant).

4 Org : remplacer markdown ?

La première utilisation d'org est de créer des documents formatés en mode texte. Il dispose pour cela de commandes assez similaires au markdown, mais plus étendues. Cela va permettre de produire des documents dont le formatage sera d'une qualité légèrement au dessus du markdown (et avec quelques astuce, il pourra même donner une illusion de qualité correcte).

NB : les commandes commençant par #+ doivent obligatoirement se trouver en début de ligne (pas de lettres, chiffre, … avant)

Fonctionnalité Ecriture
Titre \(*\) puis \(**\) puis \(***\) selon le niveau hiérachique
Liste - ou +
Liste numérotée 1.
Emphase entre *, entre /, entre +, entre _, entre ~ (combinables)
Liens (images, web, …) \([ [[]][[url] [texte alternatif]]]]\)
Code #+begin_src nom_langage CODE #+end_src
Formule \(\LaTeX\) Entre $ ou \(\[\) CODE LATEX \(\]\)
Conserver les espaces et tabulations #+begin_verse TEXTE #+end_verse
Citations #+begin_quote /CITATION #+end_quote
Centrer #+begin_center TEXTE #+end_center
Coller à droite #+begin_right TEXTE #+end_right
Note de bas de page \([fn:numero]\) menu de notes de bas de page : C-c C-x f

Pour une liste plus complète (cases à cocher, etc), le manuel vous aidera, en utilisant C-f, à condition que vous ayez une idée de ce que vous cherchez.

5 Configuration d'emacs

La présentation préalable du formatage de texte en orgmode va permettre de construire des fichiers de configuration clairs est assez facilement maintenable. La configuration va posséder deux fichiers principaux, le premier étant principalement un fichier de démarrage du second.

5.1 Avant de commencer

  • Supprimer vos fichiers de configuration d'emacs : dans votre $HOME, lister les fichier qui contiennent la chaîne de caractères emacs ls -al |grep emacs et les effacer (ou les renommer avec une extension telle que .old dans l'éventualité où on désirerait y avoir accès dans le futur), cela permettra par la suite d'être certain que c'est le fichier prévu dans lequel se fera la configuration.
  • Créer un répertoire .emacs.d mkdir ~/.emacs.d && cd ~/.emacs.d et dans ce répertoire :
    • un fichier init.el touch ~/.emacs.d/init.el, qui contiendra le fichier d'amorçage du vrai fichier de configuration d'emacs
    • un fichier myinit.org touch ~/.emacs.d/config.org, qui contient la configuration commentée d'emacs (c'est ce fichier qui nous est le plus utile)
    • un répertoire img mkdir ~/.emacs.d/img pour stocker quelques images (peut-être)
    • un fichier mes_macros.el touch ~/.emacs.d/mes_macros.el qui contiendra les macros que vous voulez charger à chaque démarrage

5.2 git

Pour ceux qui savent utiliser un serveur git (gitlab, github), une excellente idée est de créer un projet qui contient ces fichiers, auxquels s'ajouteront quelques autres fichiers une fois découvertes d'autres fonctionnalités d'emacs (carnet d'adresse, rendez-vous, emploi du temps, …). En général on ne réalse pas le suivi des greffons, à moins que ce soient des créations personnelles ou introuvables. Un gestionnaire de version permettra :

  • de retrouver sa configuration habituelle lors d'un changement de poste de travail (il faudra avoir les droits et un peu de temps, puisque tous les greffons seront à recharger, mais cela ne devrait nécessiter aucune intervention, si ce n'est un pull).
  • en cas de pépin sur le fichier de configuration, d'utiliser les fonctionnalité de git afin de recréer une version qui fonctionne et de trouver l'origine de vos ennuis.

Même si la seule chose que l'on sait faire sur git, c'est archiver (et cela prend moins d'une demi heure à apprendre avec n'importe quel tutoriel, et 5-10 minutes avec un camarade), il est intéressant de l'utiliser. Le jour où vous aurez un pépin, vous pourrez alors demander de l'aide à un collègue ou apprendre les fonctions de récupération… les données pour s'en sortir existeront !

5.3 ~/.emacs.d/init.el

L'extension 'el' indique que le fichier est écrit en emacs-lisp qui est le langage utilisé pour programmer emacs. Ce fichier sera chargé au démarrage d'emacs. Il va contenir :

  • une accélération du démarrage d'emacs

    (setq max-lisp-eval-depth 10000)
    (setq max-specpdl-size 10000)
    (require 'package)
    (setq package-enable-at-startup nil)
    
  • la configuration des adresses des dépots de paquets (le dépot par défaut ne contient pas énormément de paquets, la source usuelle est melpa)

    (setq package-archives '(("ELPA"  . "http://tromey.com/elpa/")
                             ("gnu"   . "http://elpa.gnu.org/packages/")
                             ("melpa" . "https://melpa.org/packages/")
                             ("org"   . "https://orgmode.org/elpa/")))
    (package-initialize)
    
    • Une fois ces dépôts connus d'emacs, rafraîchir la liste des greffons disponibles : M-x package-refresh-contents
    • Et afficher la liste des greffons mise à jour : M-x package-list-packages
  • le chargement du gestionnaire de greffons qui va permettre d'installer, et configurer des greffons plus aisément

    (unless (package-installed-p 'use-package)
            (package-refresh-contents)
            (package-install 'use-package))
    
  • le chargement du vrai fichier de configuration (ne pas l'appeler init.org, c'est le nom interdit, car il va être transformé en même nom.el et cela effacerait le fichier précédent)

    (org-babel-load-file (expand-file-name "~/.emacs.d/myinit.org"))
    

Lorsqu'on modifie des paramètres en utilisation usuelle d'emacs (options, installation de packages, …), les modifications sont sauvegardées dans ce fichier. C'est donc une bonne idée de temps en temps d'aller y faire le ménage, et de transférer ce qui est réellement à conserver dans le fichier myinit.org, et revenir pour ce fichier à quelque chose d’extrêmement court (moins d'une page).

5.4 Organisation du fichier ~/.emacs.d/config.org

Ce fichier va contenir du texte, et les parties qui contiendront du code seront entourées des balises

  • avant : #+begin_src emacs-lisp
  • après : #+end_src

NB : si vous utilisez un snippet d'insertion, il va vraisemblablement ajouter d'autres éléments, (en particulier :tangle yes) qu'il faudra effacer sous peine que rien ne fonctionne. Je conseille donc comme snippet <s TAB qui ne met rien de trop:).

Lors de l'appel dans le fichier init.el, un fichier myinit.el sera créé qui ne contiendra que ce qui se trouve entre ces balises, et qui sera chargé au démarrage.

Il est maintenant possible de créer des rubriques, des sous rubriques, des explications… les seules choses qui seront exécutées sont celles entre les balises de code ! En programmation, on appelle cela du 'literate programing', une thématique qui sera développée dans une autre partie de ce document.

5.5 Dernières recommandations

Avant de faire des installations, il y a quelques points à garder à l'esprit :

  • penser à mettre à jour la liste des packages avant de procéder à des installations, au risque d'essayer de charger un greffon V2.12345, alors que la version disponible sur le dépôt est maintenant la version V2.12346,
  • beaucoup de greffons sont en réalité des interfaces avec des programmes sous Linux, et si le programme lui même n'est pas installé, alors l'interface crée un lien entre emacs et … ce qui a souvent peu d'effets intéressants,
  • installer 10 greffons d'un coup, cela ne marche pas souvent et on ne sait pas très bien quoi en faire, la moindre petite ânerie et plus rien ne fonctionne, il vaut donc mieux y aller petit bout par petit bout, aller voir la page du greffon que l'on installe, regarder les exemples… après des années, on est efficace, mais on découvre toujours emacs.
  • une stratégie possible est d'installer une multitude de greffons sans trop se préoccuper de ce que l'on fait (au contraire de ce qui est proposé au point précédent), les faire fonctionner comme on peut pendant un certain temps (6 mois ? un an ?) puis de tout mettre à la poubelle pour commencer votre vrai premier fichier de config.
  • pour débugger le fichier de config, on démarre avec emacs --debug-init. Si les messages d'erreurs ne permettent pas de localiser l'origine des ennuis, on procède par dichotomie :
    1. Sauvegarder le fichier de départ (si possible avoir un gestionnaire de version : git), lorsqu'on corrige, on fait souvent empirer les choses…
    2. Procéder par dichotomie : commenter la deuxième moitié du code, voir si l'erreur perdure

      • si oui, commenter la deuxième moitié de la partie non commentée
      • si non, dé-commenter la première moitié de la partie commentée

      Même si cette méthode peut sembler archaïque et fastidieuse, elle permet en 30 essais au maximum on trouve la première ligne fautive dans un fichier d'un milliard de lignes… et est souvent beaucoup plus efficace que de chercher en relisant tout l'espace qu'on a mis en trop.

  • En insistant lourdement : conserver des sauvegardes des fichiers de config –> git !!!

6 Fichier de configuration documenté

Ah-Finally-got-my-Emacs-Setup-Just-How-I-Like-It-v2.jpg

Figure 7 : Clef en main, c'est ce qu'avait dit le vendeur…


Ce fichier a été écrit pour une utilisation d'emacs en mode fenêtré sur un système linux. Ce n'est pas une configuration 'définitive', ce sont uniquement quelques greffons et paramètres auxquels vous pouvez penser pour votre propre configuration.

6.1 Fonctionnement interne

Cette partie regroupe des fonctions qui modifient le fonctionnement d'emacs.

6.1.1 Emacs serveur

Emacs avec tous les greffons qui suivent risque de devenir long à charger… cela pause problème lorsqu'on désire uniquement éditer une ligne dans un fichier, ou faire des modifications mineures… Il existe plusieurs solutions : lancer emacs -Q ou un autre éditeur… bof!

La solution est de lancer emacs sous la forme d'un serveur, les prochaines instances d'emacs ne chargeront pas emacs mais uniquement ajouteront un client, ce qui gagne presque tous les avantages. Pour lancer les prochains emacs, la commande ne sera pls emacs mais emacsclient -c. Il est alors une bonne idée de créer un alias sur cette commande (genre alias ec=emacsclient -c -a "" que l'on ajoute au fichier ~/.bashrc

(server-start)

Il existe une autre façons de garder emacs en tâche de fond, en utilisant des daemons, ce qui est expliqué ici (le 'init script example 2' peut être un bon boint de départ).

6.1.2 Asynchrone

Ce greffon permet lorsque cela est possible de rendre les processus asynchrone (des processus indépendants qui n'attendent pas sans raison que d'autres se terminent), cela accélère parfois grandement emacs lorsque des processus longs sont lancés depuis Emacs.

(use-package async
  :ensure t
  :init (dired-async-mode 1)
  :diminish)

6.1.3 Réglage du garbage collector (non activé)

Réglage du garbage collector. Cette fonction est actuellement désactivée, elle semble ralentir mon système au lieu de l'accélérer sur cette machine.

(use-package gcmh
  :ensure t
  :demand t
  :init
  (setq gcmh-verbose             t
        gcmh-lows-cons-threshold #x800000
        gcmh-high-cons-threshold most-positive-fixnum
        gcmh-idle-delay          3600)
  :config
  (gcmh-mode)
  :diminish)

6.1.4 Correction de la vitesse de sauvegarde lente

(setq vc-handled-backends nil)

6.1.5 Rechargement automatique des fichiers modifiés

Lorsqu'un buffer affiche un fichier, et que ce fichier est modifié (par exemple c'est le résultat d'une compilation, et on a re-compilé) alors le buffer est rafraîchit de façon à bien afficher la dernière version.

(use-package autorevert
  :ensure t
  :diminish
  :config
  (setq auto-revert-verbose t)
  :hook (after-init-hook . global-auto-revert-mode))

  (setq global-auto-revert-mode t)

6.1.6 Undo : C-_, redo : M-_, naviguer dans l'arbre : C-x u

Le système d'undo est un peu difficile à appréhender, ce greffon permet de naviguer dans l'arborescence des undo/redo plus aisément.

Pour rappel, lorsqu'on s'intéresse uniquement aux dernières actions, et qu'il n'est pas nécessaire de voir l’arborescence :

C-_
pour annuler
M-_
pour annuler le annuler
(use-package undo-tree
  :ensure t
  :config
 (progn
    (global-undo-tree-mode)
    (setq undo-tree-visualizer-timestamps t)
    (setq undo-tree-visualizer-diff t)))

6.1.7 Copies de sauvegarde

Cette partie gère les options de suavegarde automatique et de copie de sauvegarde.

 ;; choice of the backup directory
(defconst my-backup-dir
  (expand-file-name (concat user-emacs-directory "backups")))

(setq make-backup-files t ;; make backup first time a file is saved
      version-control t   ;; number and keep versions of backups
      backup-by-copying t ;; and copy (don't clobber symlinks) them to...
      backup-directory-alist `(("." . ,my-backup-dir)) ;; ...here
      kept-new-versions 2
      kept-old-versions 5
      delete-old-versions t ;; don't ask about deleting old versions
      vc-make-backup-files 0 ;; don't backup files under version control (git/svn/etc.)
      ;;make-backup-files nil ;;No annoying "~file.txt"
      ;;auto-save-default nil ;;no auto saves to #file#
      auto-save-interval 180 ;; Auto save "file" to "#file#" every xxx (default 300)
      )

;; if no backup directory exists, then create it:
(if (not (file-exists-p my-backup-dir))
    (mkdir my-backup-dir t))

6.1.8 Modification du yes/no

Remplacer les laborieux yes/no par y/n

(fset 'yes-or-no-p 'y-or-n-p)

6.1.9 Mon nom et mon e-mail

(setq user-full-name "Yves-Jean Daniel"
      user-mail-address "y-jean.daniel@uca.fr")

6.1.10 Onglets (non activé)

Utiliser emacs avec des onglets ne me semble pas être la logique d'emacs, mais c'est possible

6.1.11 Autres modificateurs

Suppression des doublons dans l'historique des commandes:

(setq history-delete-duplicates t)

6.2 Macros et fichier de config

Cette partie regroupe ce qui concerne les macros personnelles ainsi que les fichiers de configuration d'emacs.

6.2.1 Chargement de mes macros personnelles

(load-file "~/.emacs.d/mes_macros.el")

6.2.2 Accéder rapidement au fichier de config C-c e

Nouvelle fonction pour accéder rapidement au fichier de configuration, activée par C-c e ('c' comme config, 'e' comme édition pour s'en rappeler)

(defun config-visit ()
  (interactive)
  (find-file "~/.emacs.d/myinit.org"))
(global-set-key (kbd "C-c e") 'config-visit)

6.2.3 Recharger rapidement le fichier de config C-c r

Nouvelle fonction pour charger rapidement le fichier de configuration, activée par C-c r ('c' comme config, 'r' comme recharger pour s'en rappeler)

(defun config-reload ()
  "Reloads ~/.emacs.d/config.org at runtime"
  (interactive)
  (org-babel-load-file (expand-file-name "~/.emacs.d/myinit.org")))
(global-set-key (kbd "C-c r") 'config-reload)

6.3 Gestion de projet

Le but de projectile est de permettre une navigation aisée parmi les différents fichiers ou buffers d'un projet, ainsi que de fournir des commandes qui lui sont relatives (rechercher un élément dan le projet, compiler, …). Les éléments du projet peuvent aisément être répertoriés grâce au répertoire git (il faut donc avoir crée un projet git pour que cette fonctionnalité soit active, mais il existe d'autres façons de créer un projet).

C-c p donne accès à la branche de commandes liées à projectile.

  (use-package projectile
    :ensure t
    :init
    (projectile-mode 1)
    (define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)
    :diminish)
  (use-package helm-projectile
    :ensure t
    :config
    (helm-projectile-on))
(use-package hydra
  :ensure t)

(defhydra hydra-projectile-other-window (:color teal)
  "projectile-other-window"
  ("f"  projectile-find-file-other-window        "file")
  ("g"  projectile-find-file-dwim-other-window   "file dwim")
  ("d"  projectile-find-dir-other-window         "dir")
  ("b"  projectile-switch-to-buffer-other-window "buffer")
  ("q"  nil                                      "cancel" :color blue))

(defhydra hydra-projectile (:color teal
                            :hint nil)
  "
     PROJECTILE: %(projectile-project-root)

     Find File            Search/Tags          Buffers                Cache
------------------------------------------------------------------------------------------
_s-f_: file            _a_: ag                _i_: Ibuffer           _c_: cache clear
 _ff_: file dwim       _g_: update gtags      _b_: switch to buffer  _x_: remove known project
 _fd_: file curr dir   _o_: multi-occur     _s-k_: Kill all buffers  _X_: cleanup non-existing
  _r_: recent file                                               ^^^^_z_: cache current
  _d_: dir

"
  ("a"   projectile-ag)
  ("b"   projectile-switch-to-buffer)
  ("c"   projectile-invalidate-cache)
  ("d"   projectile-find-dir)
  ("s-f" projectile-find-file)
  ("ff"  projectile-find-file-dwim)
  ("fd"  projectile-find-file-in-directory)
  ("g"   ggtags-update-tags)
  ("s-g" ggtags-update-tags)
  ("i"   projectile-ibuffer)
  ("K"   projectile-kill-buffers)
  ("s-k" projectile-kill-buffers)
  ("m"   projectile-multi-occur)
  ("o"   projectile-multi-occur)
  ("s-p" projectile-switch-project "switch project")
  ("p"   projectile-switch-project)
  ("s"   projectile-switch-project)
  ("r"   projectile-recentf)
  ("x"   projectile-remove-known-project)
  ("X"   projectile-cleanup-known-projects)
  ("z"   projectile-cache-current-file)
  ("`"   hydra-projectile-other-window/body "other window")
  ("q"   nil "cancel" :color blue))

6.4 Traitement de fichiers

6.4.1 Explorateur de fichiers

Treemacs est un explorateur de fichier graphique, permettant d'afficher l'arborescence et d'effectuer des commandes usuelles de manipulation de fichier.

La configuration qui suit est la copie de la configuration proposée par le créateur. Elle est aisément adaptable. Elle comprend également les liens avec d'autres greffons, qui ne sont pas nécessairement installés dans votre configuration.

  (use-package treemacs
  :ensure t
  :defer t
  :init
  (with-eval-after-load 'winum
    (define-key winum-keymap (kbd "M-0") #'treemacs-select-window))
  :config
  (progn
    (setq treemacs-collapse-dirs                 (if treemacs-python-executable 3 0)
          treemacs-deferred-git-apply-delay      0.5
          treemacs-directory-name-transformer    #'identity
          treemacs-display-in-side-window        t
          treemacs-eldoc-display                 t
          treemacs-file-event-delay              5000
          treemacs-file-extension-regex          treemacs-last-period-regex-value
          treemacs-file-follow-delay             0.2
          treemacs-file-name-transformer         #'identity
          treemacs-follow-after-init             t
          treemacs-git-command-pipe              ""
          treemacs-goto-tag-strategy             'refetch-index
          treemacs-indentation                   2
          treemacs-indentation-string            " "
          treemacs-is-never-other-window         nil
          treemacs-max-git-entries               5000
          treemacs-missing-project-action        'ask
          treemacs-move-forward-on-expand        nil
          treemacs-no-png-images                 nil
          treemacs-no-delete-other-windows       t
          treemacs-project-follow-cleanup        nil
          treemacs-persist-file                  (expand-file-name ".cache/treemacs-persist" user-emacs-directory)
          treemacs-position                      'left
          treemacs-recenter-distance             0.1
          treemacs-recenter-after-file-follow    nil
          treemacs-recenter-after-tag-follow     nil
          treemacs-recenter-after-project-jump   'always
          treemacs-recenter-after-project-expand 'on-distance
          treemacs-show-cursor                   nil
          treemacs-show-hidden-files             t
          treemacs-silent-filewatch              nil
          treemacs-silent-refresh                nil
          treemacs-sorting                       'alphabetic-asc
          treemacs-space-between-root-nodes      t
          treemacs-tag-follow-cleanup            t
          treemacs-tag-follow-delay              1.5
          treemacs-user-mode-line-format         nil
          treemacs-user-header-line-format       nil
          treemacs-width                         35)

    ;; The default width and height of the icons is 22 pixels. If you are
    ;; using a Hi-DPI display, uncomment this to double the icon size.
    ;;(treemacs-resize-icons 44)

    (treemacs-follow-mode t)
    (treemacs-filewatch-mode t)
    (treemacs-fringe-indicator-mode t)
    (pcase (cons (not (null (executable-find "git")))
                 (not (null treemacs-python-executable)))    
      (`(t . t)
       (treemacs-git-mode 'deferred))
      (`(t . _)
       (treemacs-git-mode 'simple))))
  :bind
  (:map global-map
        ("M-0"       . treemacs-select-window)
        ("C-* t 1"   . treemacs-delete-other-windows)
        ("C-* t t"   . treemacs)
        ("C-* t B"   . treemacs-bookmark)
        ("C-* t C-t" . treemacs-find-file)
        ("C-* t M-t" . treemacs-find-tag)))

(use-package treemacs-evil
  :after treemacs evil
  :ensure t)

(use-package treemacs-projectile
  :after treemacs projectile
  :ensure t)

(use-package treemacs-icons-dired
  :after treemacs dired
  :ensure t
  :config (treemacs-icons-dired-mode))

(use-package treemacs-magit
  :after treemacs magit
  :ensure t)

(use-package treemacs-persp
  :after treemacs persp-mode
  :ensure t
  :config (treemacs-set-scope-type 'Perspectives))

6.4.2 la commande unix sed dans emacs C-c C-p et C-c C-e

Ce greffon permet, après avoir invoqué grep M-x grep et basculé dans le buffer, d'éditer le texte. Par exemple, on recherche 'ajout' dans tous les fichiers du répertoire, et on remplace ce texte par 'ajouter'. C'est en réalité un équivalent à la commande unix sed, mais avec la puissance et le confort d'édition d'emacs. Pour éditer C-c C-p, pour sauvegarder les modifications, C-c C-e.

(use-package wgrep
  :ensure t)

(use-package wgrep-ag
  :ensure t)

(require 'wgrep-ag)

Exemple :

  • Créer deux fichiers, qui contiennent tous les deux le texte "hello", et n'importe quoi d'autre
  • M-x grep RET puis compléter la commande par hello * (chercher le texte "hello" dans tous les fichiers du répertoire)
  • Entrer dans le mode édition par C-c C-p
  • Remplacer tous les "hello" par bonjour (M-; puis "hello" puis "bonjour" puis !)
  • Valider le travail C-c C-e
  • Les fichiers qui ont reçu des modifications font maintenant partie de la liste des buffers ouverts, il faudra penser à les sauvegarder si on désire conserver les modifications.

6.4.3 Ripgrep

Ce package est principalement utilisé dans projectile afin de réaliser des recherches extrêmement rapides à l'aide de grep. Penser à l'installer sous linux. La ligne de commande usuelle est cmd | rg regexp

6.5 Interface

6.5.1 Suppression des éléments en excès

Cette section regroupe la suppression des éléments qui sont superflus dans l'interface de base d'emacs

  1. Suppression du message de démarrage
    (setq inhibit-startup-message t)
    
  2. Suppression de la barre de défilement
    (scroll-bar-mode -1)
    
  3. Suppression de la barre d'outil
    (tool-bar-mode -1)
    
  4. Suppression de la barre de menu
    ;; suppression non activée, les menus sont pratiques pour apprendre
    ;; (menu-bar-mode -1) 
    
  5. Démarrage en plein écran

    Démarrage en mode plein écran au lieu de fenêtré

    (add-to-list 'default-frame-alist '(fullscreen . maximized))
    

6.5.2 Curseur

Il est possible de remplacer le carré clignotant qui sert de curseur.

(setq-default cursor-type '(bar . 1)) ;; cursor is a bar/box/hollow/hbar

(blink-cursor-mode 1) 

Lorsque l'on passe d'un buffer à un autre, on ne voit pas toujours au premier regard où se trouve le curseur. De la même façon, lorsque l'on scroll il est fréquent qu'on le perde. Les lignes qui suivent remédient à cela.

 (use-package beacon
 :ensure
 :diminish
 :config
 (setq beacon-blink-delay 0.1)
 (setq beacon-blink-duration 0.25)
 (setq beacon-size 20))
(beacon-mode 1) ;; uncomment to activate

6.5.3 Sauvegarde des fenêtres

Il est souvent utile de mettre en plein écran un buffer… puis de revenir dans la configuration bien agencé de ses buffers. c'est le greffon winner qui va permettre cela.

(use-package winner
  :ensure t
  :hook (after-init-hook . winner-mode)
  :bind ("<C-c right>" . winner-redo)
        ("<C-c left>" . winner-undo))
(winner-mode 1)

Pour bien comrendre, ouvrez plusieurs buffers à l'écran, placez vous dans l'un des buffers, C-x 1 pour le mettre en plein écran, puis C-c left pour revenir à la configuration de fenêtres précédente.

6.5.4 Modeline

Un modificateur d'apparence qui va moderniser la barre d'état d'emacs (la barre du bas), en reprenant des éléments de spacemacs.

(use-package spaceline
  :ensure t
  :config
  (require 'spaceline-config)
  (setq spaceline-buffer-encoding-abbrev-p nil)
  (setq spaceline-line-column-p t)
  (setq spaceline-line-p nil)
  (setq powerline-default-separator (quote arrow))
  (spaceline-spacemacs-theme)
  (spaceline-helm-mode))
;; display time in powerline
(spaceline-define-segment datetime
  (shell-command-to-string "echo -n \"⏰  $(date '+%a %d %b %H:%M%p')\""))
(spaceline-spacemacs-theme 'datetime)

(use-package spaceline-all-the-icons 
  :ensure t
  :after spaceline
  :config (spaceline-all-the-icons-theme)
  (spaceline-all-the-icons--setup-anzu)
  )

6.5.5 Horloge

Réglage des paramètres de l'horloge.

(setq display-time-24hr-format t)
(setq display-time-format "%H:%M - %d %B %Y")
(display-time-mode 1)

6.5.6 Surlignage de la ligne en cours

La ligne où se trouve le curseur est surlignée, cela permet de se repèrer plus rapidement.

(global-hl-line-mode t)
(set-face-background hl-line-face "#311") ;; with tangotango theme, the red color is too clingy

6.5.7 Dashboard

Dashboard va créer l'écran de démarrage où vont apparaître les derniers projets et fichiers consultés. Il possède plusieurs dépendance (chargées dans d'autres catégories) :

(use-package dashboard
  :ensure t
  :config
  (dashboard-setup-startup-hook)
  (setq dashboard-startup-banner "~/.emacs.d/img/sandman.jpeg") ;; vous
  ;; pouvez changer l'image...
  (setq dashboard-items '((recents  . 7)
                          (bookmarks . 5)
                          (agenda . 5)
                          (registers . 5)
                          (projects . 5)))
  (setq dashboard-banner-logo-title "Back already ?")
  (setq dashboard-set-heading-icons t)
  (setq dashboard-set-file-icons t)
  (setq dashboard-set-navigator t)
  )

6.5.8 Numéros de ligne à gauche

Non activé je ne l'apprécie pas beaucoup, je préfère l'activer temporairement par M-x linum-mode lorsque j'en ai besoin.

;; (global-linum-mode 1)

Au lieu de l'activer pour tous les modes par défaut, on peut choisir de ne l'activer que pour certains modes (il est ici activé pour tous les modes de programmation), pour le désactiver, il suffit de M-x linum-mode.

(add-hook 'prog-mode-hook #'linum-mode) 

6.5.9 Thème

Un thème sombre :

;; Chargement thème tangotango
(use-package tangotango-theme
  :ensure t
  :config (load-theme 'tangotango t)
  :diminish)

Des librairies de thèmes bien adaptées à la modline.

(use-package spacegray-theme :defer t)
(use-package doom-themes
  :ensure t
  :config
  ;; Global settings (defaults)
  (setq doom-themes-enable-bold t    ; if nil, bold is universally disabled
        doom-themes-enable-italic t) ; if nil, italics is universally disabled
  (load-theme 'doom-dracula t)

  ;; Enable flashing mode-line on errors
  (doom-themes-visual-bell-config)
  ;; Enable custom neotree theme (all-the-icons must be installed!)
  (doom-themes-neotree-config)
  ;; or for treemacs users
  (setq doom-themes-treemacs-theme "doom-atom") ; use "doom-colors" for less minimal icon theme
  (doom-themes-treemacs-config)
  ;; Corrects (and improves) org-mode's native fontification.
  (doom-themes-org-config))

Il existe de nombreux thèmes accessibles depuis https://emacsthemes.com/.

6.5.10 Icônes

Ajout de pack d’icônes. Parfois, il y a un problème avec le chargement des fontes d'icônes. Une solution à alors envisager est d’exécuter (all-the-icons-install-fonts t)C-x C-e ce qui devrait forcer l'installation des fontes absentes (normalement le premier bloc de code est là pour cela, mais je ne suis pas certain qu'il fonctionne sur toutes les configurations).

(unless (member "all-the-icons" (font-family-list))
  (all-the-icons-install-fonts t))

(use-package all-the-icons 
:ensure t
:defer 0.5)
 (use-package all-the-icons-ivy
  :ensure t
  :after (all-the-icons ivy)
  :custom (all-the-icons-ivy-buffer-commands '(ivy-switch-buffer-other-window ivy-switch-buffer))
  :config
  (add-to-list 'all-the-icons-ivy-file-commands 'counsel-dired-jump)
  (add-to-list 'all-the-icons-ivy-file-commands 'counsel-find-library)
  (all-the-icons-ivy-setup))

(use-package all-the-icons-dired
  :ensure t)

(add-hook 'dired-mode-hook 'all-the-icons-dired-mode)

6.5.11 Parenthèses

  1. Parenthèses de couleur

    rainbow-delimiters permet d'avoir des délimiteurs (parenthèses, accolades, crochets dont la couleur est associée pour l'ouverture et la fermeture), très utile dans des langages à parenthèses, et utile sinon. Il est nécessaire de l'activer pour chacun des modes où on désire l'utiliser, il n'y a pas d'option pour l'activer partout. Les couleurs par défaut ne convienne pas à ma vue avec un thème sombre, il y a donc dans le fichier init.el des modificateurs des couleurs utilisées.

    (use-package rainbow-delimiters
      :hook
      (org-mode . rainbow-delimiters-mode)
      (prog-mode . rainbow-delimiters-mode)
      (latex-mode . rainbow-delimiters-mode)
      :ensure t
      :diminish
      )
    
  2. Encapsulation visible

    show-paren-mode permet de mettre en exergue une ouverture de délimiteur lorsqu'on positionne le curseur sur sa contrepartie.

    (show-paren-mode 1)
    
  3. Paires automatiques

    Ce greffon permet d'avoir automatiquement la fermeture de la paire qui vient d'être commencée, il est aisé de rajouter d'autres paires.

    (setq electric-pair-pairs '(
                               (?\{ . ?\})
                               (?\( . ?\))
                               (?\[ . ?\])
                               (?\" . ?\")
                               (?\~ . ?\~)
                               ))
    (electric-pair-mode t) 
    

6.6 Aide à la frappe

Cette partie regroupe des éléments qui facilitent la frappe.

6.6.1 Réécriture sur sélection

Lorsqu'un texte est sélectionné, écrire va remplacer le texte sélectionné. Cette option me paraît assez importante.

(delete-selection-mode t)

6.6.2 Aide aux contrôle clavier

Lorsqu'on commence à taper un contrôle clavier, dans le command buffer apparaissent après un bref instant les possibilités pour continuer à taper. C'est grâce à ce greffon que l'on peut réellement apprendre les contrôles clavier d'emacs. Par exemple, les commandes pour les rectangles commencent par C-c r, en tapant cela, on voit apparaître tous les contrôles clavier qui concernent les rectangles (plus d'autres), et cela permet de trouver rapidement des fonction nouvelles.

(use-package which-key
  :ensure t
  :config (which-key-mode)
  :diminish)  

6.7 Raccourcis clavier préfixes

Lorsqu'on travaille sur une famille de commandes, la plupart des commandes possèdent un préfixe commun. Hydra permet de ne taper ce préfixe qu'une seule fois, pour les commandes qui suivent, il suffit alors de taper le suffixe propre à la commande particulière que l'on désire effectuer. Lorsqu'un suffixe ne correspond à aucune commande, hydra est stoppé.

Il faudrait améliorer cette configuration de hydra…

Je pense qu'il vaut mieux insérer la partie hydra sur chacun des greffons concernés plutôt que d'avoir un bloc de configuration qui regroupe tout ici.

(use-package hydra 
   :ensure t
   :init 
   (global-set-key
   (kbd "C-x t")
           (defhydra toggle (:color blue)
             "toggle"
             ("a" abbrev-mode "abbrev")
             ("s" flyspell-mode "flyspell")
             ("d" toggle-debug-on-error "debug")
             ("c" fci-mode "fCi")
             ("f" auto-fill-mode "fill")
             ("t" toggle-truncate-lines "truncate")
             ("w" whitespace-mode "whitespace")
             ("q" nil "cancel")))
   (global-set-key
    (kbd "C-x j")
    (defhydra gotoline 
      ( :pre (linum-mode 1)
             :post (linum-mode -1))
      "goto"
      ("t" (lambda () (interactive)(move-to-window-line-top-bottom 0)) "top")
      ("b" (lambda () (interactive)(move-to-window-line-top-bottom -1)) "bottom")
      ("m" (lambda () (interactive)(move-to-window-line-top-bottom)) "middle")
      ("e" (lambda () (interactive)(end-of-buffer)) "end")
      ("c" recenter-top-bottom "recenter")
      ("n" next-line "down")
      ("p" (lambda () (interactive) (forward-line -1))  "up")
      ("g" goto-line "goto-line")
      ))
   )


6.7.1 Sélection magique des alentours C-q

Ce greffon permet de sélectionner à partir de la position du curseur des zones de plus en plus grande en fonction du nombre de C-q effectués. La sélection est 'intelligente', les zones sélectionnées respectent les conventions syntaxiques usuelles : lettre –> mot –> parenthèse –> phrase –> paragraphe…

(use-package expand-region
  :ensure t
  :bind ("C-q" . er/expand-region)
  :diminish)

6.7.2 Multiples curseurs C->, C-<, C-S <Mouse-1>, C-c C-,

Un greffon qui permet d’avoir plusieurs curseurs en même temps… Pour comprendre à quoi cela peut servir, vous pouvez visionner Emacs Rocks!. Pour l'utiliser, commencer par sélectionner, puis ajouter à la sélection, éditer et finalement RET. Si un saut de ligne doit être inséré, : C-j.

(use-package multiple-cursors
 :ensure t
 :bind (:map global-map
       ("C->" . mc/mark-next-like-this)
       ("C-<" . mc/mark-previous-like-this)
       ("C-c C-," . mc/mark-all-like-this)
       ("C-S-<mouse-1>" . mc/add-cursor-on-click)))
(provide 'init-multiple-cursors)

6.7.3 Effacement glouton

Lorsqu'il y a plusieurs espaces ou tabulations, le comportement par défaut des touches d'effacement est d'effacer un de ces espaces. L'activation de ce greffon va avoir comme effet de tous les supprimer. On aime… ou pas.

(use-package hungry-delete
  :ensure t
  :config
    (global-hungry-delete-mode)
  :diminish)

6.7.4 Accéder aux éléments du kill-ring M-y

Sur emacs, il existe un presse papier qu'on appelle 'kill-ring', il est un peu difficile de naviguer dans ce presse papier, le contrôle M-y va proposer une liste d'éléments plus anciens qui pourront être collés.

(setq kill-ring-max 100) ;; passer la taille du kill-ring à 100 (par défaut 60)
(use-package popup-kill-ring
  :ensure t
  :bind ("M-y" . popup-kill-ring)
  :diminish)

6.7.5 Snippets

Les snippets sont des fragments de code qui sont déjà prêts et que vous n'avez plus qu'à invoquer au lieu de les taper. Il en existe pour tous les domaines (de la recette de cuisine à la programmation en c++, en passant évidemment par \(\LaTeX\)).

Sous Emacs, on apprécie le paquet yasnippet qui contient le moteur, auquel on rajoute les snippets dont on a besoin.

(use-package yasnippet ;; le moteur
  :ensure t
  :config
    (use-package yasnippet-snippets ;; un pack de snippets
      :ensure t
      :diminish)
    (yas-reload-all)
    (yas-global-mode 1) ;; activé partout
  :diminish) 

6.7.6 Longueur des lignes

La longueur des lignes par défaut est 70 si on utilise la mise en forme automatique des lignes. Les lignes qui suivent fixent cette longueur à 80, et activent le mode 'retour à la ligne automatique' par défaut.

(setq-default auto-fill-function 'do-auto-fill)
(setq-default fill-column 80)

Dans certains cas, il est utile de désactiver l'auto-fill par M-x auto-fill-mode

6.7.7 Effacer le début de la ligne M-k

La commande C-k efface du curseur à la fin de la ligne, celle-ci efface du début de la ligne jusqu'au curseur (exclus).

(global-set-key "\M-k" '(lambda () (interactive) (kill-line 0)) )

6.8 Recherches

6.8.1 Counsel, un prérequis

counsel est un prérequis pour swiper (entre autres).

(use-package counsel
  :ensure t
  :diminish)

6.8.2 Recherche de mots/phrases dans la totalité du document

Recherche dans le document, configuration par défaut proposée par swiper

(use-package swiper
  :ensure t
  :config (progn

            (ivy-mode 1)
            (setq ivy-use-virtual-buffers t)
            (setq enable-recursive-minibuffers t)
            ;; enable this if you want `swiper' to use it
            ;; (setq search-default-mode #'char-fold-to-regexp)
            (global-set-key "\C-s" 'swiper)
            (global-set-key (kbd "C-c C-r") 'ivy-resume)
            (global-set-key (kbd "M-x") 'counsel-M-x)
            (global-set-key (kbd "C-x C-f") 'counsel-find-file)
            (global-set-key (kbd "<f6>") 'ivy-resume)
            (global-set-key (kbd "<f1> f") 'counsel-describe-function)
            (global-set-key (kbd "<f1> v") 'counsel-describe-variable)
            (global-set-key (kbd "<f1> l") 'counsel-find-library)
            (global-set-key (kbd "<f2> i") 'counsel-info-lookup-symbol)
            (global-set-key (kbd "<f2> u") 'counsel-unicode-char)
            (global-set-key (kbd "C-c g") 'counsel-git)
            (global-set-key (kbd "C-c j") 'counsel-git-grep)
            (global-set-key (kbd "C-c k") 'counsel-ag)
            (global-set-key (kbd "C-x l") 'counsel-locate)
            (global-set-key (kbd "C-S-o") 'counsel-rhythmbox)
            (define-key minibuffer-local-map (kbd "C-r")
            'counsel-minibuffer-history)
   :diminish))

6.8.3 Goto character M-s

Le go-to-char ultime (permet d'aller rapidement à un endroit à l'écran), je n'ai pris qu'un bind qui me va bien parce que je suis très lent (on tape ce que l'on cherche à l'écran, puis on attend, et après on choisit par le premier caractère), il y en a plusieurs autres, sur https://github.com/abo-abo/avy. Le contrôle clavier est M-s qui est très proche de C-s de la recherche d'expression.

Comment l'utiliser : fixer des yeux à l'écran l'endroit où vous désirez déplacer le curseur, M-s deux lettres (ou 1, ou plus, mais deux me convient bien), attendre une fraction de seconde, et taper la lettre mise en exergue… c'est magique.

(use-package avy
  :ensure t
  :bind ("M-s" . avy-goto-char-timer)
  :diminish)

6.8.4 Tags

Une fonction de rafraichissement automatique des tags. Lorqu'un tag n'est pas trouvé, la fonction lance ctags afin de faire la mise à jour des tags, et relance la recherche sur la table des tags mise à jour.

  ;;;  Jonas.Jarnestrom<at>ki.ericsson.se A smarter               
  ;;;  find-tag that automagically reruns etags when it cant find a               
  ;;;  requested item and then makes a new try to locate it.                      
  ;;;  Fri Mar 15 09:52:14 2002    
(defadvice find-tag (around refresh-etags activate)
  "Rerun etags and reload tags if tag not found and redo find-tag.              
   If buffer is modified, ask about save before running etags."
  (let ((extension (file-name-extension (buffer-file-name))))
    (condition-case err
        ad-do-it
      (error (and (buffer-modified-p)
                  (not (ding))
                  (y-or-n-p "Buffer is modified, save it? ")
                  (save-buffer))
             (er-refresh-etags extension)
             ad-do-it))))
(defun er-refresh-etags (&optional extension)
  "Run etags on all peer files in current dir and reload them silently."
  (interactive)
  (shell-command (format "etags *.%s" (or extension "el")))
  (let ((tags-revert-without-query t))  ; don't query, revert silently          
    (visit-tags-table default-directory nil)))

6.9 Orthographe

6.9.1 Correcteur syntaxique

Il existe plusieurs correcteur syntaxiques, en particulier ispell (correcteur par défaut), hunspell (utilisé par LibreOffice, Mozilla, Google, que je vous propose d'installer) et aspell (que beaucoup de programmeurs ont longtemps choisi).

Pour hunspell, il est nécessaire d'installer au préalable des packages en ligne de commande (à moins qu'ils ne soient présents par défaut dans votre distribution).

  1. En ligne de commande, installer hunspell (avant d'installer, vérifier sur le net qu'il n'y a rien de spécial à faire pour votre distribution particulière)
  2. En ligne de commande, installer hunspell-fr-classical (un dictionnaire français) et hunspell-en-us (un dictionnaire anglais us)

Après installation dans emacs, les deux principales commandes sont :

  1. M-ispell pour vérifier tout ou la sélection en cours
  2. M-$ pour vérifier un mot, ou simplement le corriger lorsqu'on sait qu'on l'a mal orthographié

Vous noterez que bien que le moteur soit maintenant hunspell les commandes font toujours référence à ispell (vous pouvez vérifier que hunspell est utilisé par M-x ispell-check-version).

(setq ispell-local-dictionary-alist- 
      '(("francais" "[[:alpha:]]" "[^[:alpha:]]" "[']" nil ("-d" "fr") nil utf-8)
        ("en_US" "[[:alpha:]]" "[^[:alpha:]]" "[']" nil ("-d" "en_US") nil utf-8)
        ))
(setq ispell-program-name "hunspell"          ; Use hunspell to correct mistakes
      ispell-dictionary   "francais")

La fonction qui suit permet de basculer du dictionnaire français au dictionnaire anglais us par C-c d.

(defun switch-dictionary-fr-en ()
  "Switch french and english dictionaries."
  (interactive)
  (let* ((dict ispell-current-dictionary)
         (new (if (string= dict "francais") "en_US"
                   "francais")))
    (ispell-change-dictionary new)
    (message "Switched dictionary from %s to %s" dict new)))

(global-set-key (kbd "C-c d") 'switch-dictionary-fr-en)

6.9.2 Correction orthographique à la volée C-c f

Ici la configuration va permettre de souligner les mots mal orthographiés, y compris dans les commentaires de code. Le contrôle clavier C-c f permet d'exécuter i-spell (ou son remplaçant) sur le dernier (= avant) mot mal orthographié.

;; (add-hook 'prog-mode-hook 'flyspell-prog-mode) ;; if you write text with a
;; lot of text, it is possible to activte it, the problem is that it suggests errors
;; when you put code inside ""
(global-set-key (kbd "C-c f") 'flyspell-check-previous-highlighted-word)

;;-------------
;; Text mode
;;-------------
(add-hook 'text-mode-hook 'flyspell-mode)
(add-hook 'prog-mode-hook 'flyspell-prog-mode)

;; Highlight BUG FIXME TODO NOTE keywords in the source code.
(add-hook 'find-file-hook
          (lambda()
            (highlight-phrase "\\(BUG\\|FIXME\\|TODO\\|NOTE\\):")))

6.10 Fenêtres

Gestionnaire de fenêtres, pour naviguer de façon plus agréable entre les fenêtres A partir de 3 fenêtres, un numéro s'affiche après C-x o dans chaque fenêtre, en le tapant, le curseur bascule dans cette fenêtre

(use-package ace-window
  :ensure t
  :init (progn (global-set-key [remap other-window] 'ace-window)
               (custom-set-faces
                '(aw-leading-char-face
                  ((t (:inherit ace-jump-face-foreground :height 7.0))))))
  :diminish)

6.11 Orgmode

6.11.1 Exécution de code dans un fichier org: langages reconnus

org-babel va permettre d'exécuter du code à l'intérieur d'un fichier org. Les résultats pourront être affichés ou utilisés dans des blocs de codes ultérieurs. Il est intégré par défaut, mais il peut être nécessaire d'ajouter certains langages qui ne sont pas inclus par défaut.

(org-babel-do-load-languages
   'org-babel-load-languages
   '((ditaa      . t)
     (C          . t)
     (dot        . t)
     (emacs-lisp . t)
     (scheme     . t)
     (gnuplot    . t)
     (haskell    . t)
     (latex      . t)
     (js         . t)
     (ledger     . t)
     (matlab     . t)
     (ocaml      . t)
     (octave     . t)
     (plantuml   . t)
     (python     . t)
     (R          . t)
     (ruby       . t)
     (screen     . nil)
     (scheme     . t)
     (shell      . t)
     (sql        . t)
     (sqlite     . t)))
(setq org-babel-python-command "python3")

6.11.2 Tangle automatique

Lorsque le fichier est sauvegardé, les blocs de code disposant de l'option tangle: yes vont automatiquement exécuter la commande 'tangle' qui va extraire le code du fichier pour produire le/les fichier(s) code source.

(add-hook 'org-mode-hook
          (lambda ()
            (add-hook 'after-save-hook
                      (lambda ()
                         (org-babel-tangle))
                      nil
                      'make-it-local)))

6.11.3 Exécution des blocs de code non bloquante

Lorsqu'on exécute C-c C-c un bloc de code placé entre deux balises begin_src et end_src on 'perd la main' par défaut jusqu'à la fin de la commande (par exemple dans un bloc bash vous exécuter chromium, et ne recouvrez donc la main qu'à la fermeture de ce logiciel). Cette option permet de récupérer la main immédiatement.

(setq org-export-in-background t)
  1. Exécution de codes longs dans des balises src
    (use-package ob-async
      :hook (org-load . (lambda () (require 'ob-async)))
      :init
      (setq ob-async-no-async-languages-alist '("jupyter-python" "jupyter-R"
                                                "jupyter-julia" "ipython")))
    

6.11.4 Exécution de bloc de code sans validation

Par défaut, lorsqu'on exécute C-c C-c un bloc de code placé entre deux balises begin_src et end_src, on reçoit un message de demande de validation. Cette option permet d'éviter cette validation.

(setq org-confirm-babel-evaluate nil)

6.11.5 Puces plus jolies

Le module org bullet permet d'améliorer l'apparence des titres et de puces.

(use-package org-bullets
    :ensure t
    :config  (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1)))
    :diminish)
;; (setq org-bullets-bullet-list '("■" "◆" "▲" "▶")) ;; If you want to change
;;    the symbols, but I like the defaults

6.11.6 Remplacement des … par quelque chose de plus joli

A la fin des éléments repliés, par défaut le symbole est '…', cette commande permet de remplacer ce symbole par un visuellement plus évocateur.

(setq org-ellipsis " ⬎")

6.11.7 Mise en forme du code en orgmode

Par défaut le code n'est pas indenté selon les règles usuelles lorsqu'il est inséré en orgmode dans un bloc de code. La commande suivante remet l'indentation en place pour les blocs de code.

(setq org-src-tab-acts-natively t)

6.11.8 Suppression de la demande d'autorisation d'exécution de code

Par défaut, il y a un message pour demander à l'utilisateur d'autoriser l'exécution de tout fragment de code, cette ligne modifie cette option.

(setq org-confirm-babel-evaluate nil)

6.11.9 Exports de fichier org

Les fichiers org peuvent être compilés en différents autres langages par C-x C-e, la liste des langages/formats dans lesquels on peut exporter peut être augmentée par différents greffons.

  1. reveal : présentations type powerpoint

    Reveal nécessite un apprentissage par lui-même. Une page d'introduction pour faire les premières présentation peut être https://opensource.com/article/18/2/how-create-slides-emacs-org-mode-and-revealjs

    (use-package ox-reveal
       :ensure t)
    
    (setq org-reveal-root "http://cdn.jsdelivr.net/npm/reveal.js")
    (setq org-reveal-mathjax t)
    
  2. Twitter

    Lors d'un export, il faudra alors choisir 'export to TWBS HTML""

    (use-package ox-twbs
    :ensure t)
    

6.11.10 Fin de ligne plus claires

(add-hook 'org-mode-hook
          '(lambda ()
             (visual-line-mode 1)))

6.11.11 Configuration pour hydra (à améliorer)

Cf. hydra si nécessaire.

(global-set-key
    (kbd "C-c t")
    (defhydra hydra-global-org (:color blue)
      "Org"
      ("t" org-timer-start "Start Timer")
      ("s" org-timer-stop "Stop Timer")
      ("r" org-timer-set-timer "Set Timer") ; This one requires you be in an orgmode doc, as it sets the timer for the header
      ("p" org-timer "Print Timer") ; output timer value to buffer
      ("w" (org-clock-in '(4)) "Clock-In") ; used with (org-clock-persistence-insinuate) (setq org-clock-persist t)
      ("o" org-clock-out "Clock-Out") ; you might also want (setq org-log-note-clock-out t)
      ("j" org-clock-goto "Clock Goto") ; global visit the clocked task
      ("c" org-capture "Capture") ; Don't forget to define the captures you want http://orgmode.org/manual/Capture.html
            ("l" org-capture-goto-last-stored "Last Capture"))
    )

6.11.12 Auto mise à jour images

Pour recharger automatiquement les images d'un document orgmode.

(eval-after-load 'org
  (add-hook 'org-babel-after-execute-hook 'org-redisplay-inline-images))

6.12 eaf

6.12.1 eaf core

(use-package eaf
    :load-path "~/.emacs.d/site-lisp/emacs-application-framework" ; Set to "/usr/share/emacs/site-lisp/eaf" if installed from AUR
    :custom
    ; See
    ; https://github.com/emacs-eaf/emacs-application-framework/wiki/Customization
    (eaf-browser-continue-where-left-off t)
    (eaf-browser-enable-adblocker t)
    (browse-url-browser-function 'eaf-open-browser)
    :config
    (defalias 'browse-web #'eaf-open-browser))
  ;;  (eaf-bind-key scroll_up "C-n" eaf-pdf-viewer-keybinding)
  ;;  (eaf-bind-key scroll_down "C-p" eaf-pdf-viewer-keybinding)
  ;;  (eaf-bind-key take_photo "p" eaf-camera-keybinding)
  ;;  (eaf-bind-key nil "M-q" eaf-browser-keybinding)) ;; unbind, see more in the Wiki

  (add-to-list 'load-path "~/.emacs.d/site-lisp/eaf-browser/")

  (require 'eaf-browser)

6.12.2 html browser

  (add-to-list 'load-path "~/.emacs.d/site-lisp/eaf-browser/")

  (require 'eaf-browser)
(eaf-setq eaf-browser-enable-adblocker "true")


6.12.3 pdf

(add-to-list 'load-path "~/.emacs.d/site-lisp/eaf-pdf-viewer/")
(require 'eaf-pdf-viewer)

6.12.4 org previewer

6.12.5 eaf other modules

(require 'eaf-org-previewer)
(require 'eaf-airshare)
(require 'eaf-mindmap)

(require 'eaf-system-monitor)
(require 'eaf-netease-cloud-music)
(require 'eaf-terminal)
(require 'eaf-demo)
(require 'eaf-file-browser)
(require 'eaf-vue-demo)
(require 'eaf-jupyter)
(require 'eaf-file-sender)
(require 'eaf-browser)
(require 'eaf-file-manager)
(require 'eaf-image-viewer)
(require 'eaf-music-player)
(require 'eaf-markdown-previewer)
(require 'eaf-camera)
(require 'eaf-video-player)
  1. airshare
  2. mindmap
  3. mermaid
  4. system monitor
  5. netease cloud music
  6. terminal
  7. demo
  8. file browser
  9. vue demo
  10. jupyter
  11. file sender
  12. file manager
  13. image preview
  14. music player
  15. markdown previewer
  16. camera
  17. vidéo player

6.13 Complétion

6.13.1 Ivy

C'est un prérequis pour de nombreux modules de complétion.

   (ivy-mode 1)
   (setq ivy-use-virtual-buffers t)
   (global-set-key (kbd "C-c C-r") 'ivy-resume)
   (global-set-key (kbd "<f6>") 'ivy-resume)
;;Plus cool completion approximative dans le buffer
(setq ido-enable-flex-matching t)
(ido-mode 1)

6.13.2 Complétion de texte

Il existe actuellement deux greffons de complétion très utilisés, auto-complete et company. J'ai une préférence pour company qui est un peu plus moderne. Les touches pour naviguer dans les propositions sont :

  • C-n suivant
  • C-p précédent
  • C-SPC annuler
(use-package company
  :ensure t
  :init (global-company-mode)
  :config
    (setq company-idle-delay 0)
    (setq company-minimum-prefix-length 3)
  :diminish company-mode)

(with-eval-after-load 'company
  (define-key company-active-map (kbd "M-n") nil)
  (define-key company-active-map (kbd "M-p") nil)
  (define-key company-active-map (kbd "C-n") #'company-select-next)
  (define-key company-active-map (kbd "C-p") #'company-select-previous)
  (define-key company-active-map (kbd "SPC") #'company-abort))

6.13.3 Helm

Helm regroupe un grand nombre de fonctions de complétion, en particulier dans le mini-buffer (là où sont écrites les commandes).

  (use-package helm
  :ensure t
  :bind
  ("C-x C-f" . 'helm-find-files)
  ("C-x C-b" . 'helm-buffers-list)
  ("M-x" . 'helm-M-x)
  :config
  (defun my/helm-hide-minibuffer ()
    (when (with-helm-buffer helm-echo-input-in-header-line)
      (let ((ov (make-overlay (point-min) (point-max) nil nil t)))
        (overlay-put ov 'window (selected-window))
        (overlay-put ov 'face
                     (let ((bg-color (face-background 'default nil)))
                       `(:background ,bg-color :foreground ,bg-color)))
        (setq-local cursor-type nil))))
  (add-hook 'helm-minibuffer-set-up-hook 'my/helm-hide-minibuffer)
  (setq helm-autoresize-max-height 0
        helm-autoresize-min-height 40
        helm-M-x-fuzzy-match t
        helm-buffers-fuzzy-matching t
        helm-recentf-fuzzy-match t
        helm-semantic-fuzzy-match t
        helm-imenu-fuzzy-match t
        helm-split-window-in-side-p nil
        helm-move-to-line-cycle-in-source nil
        helm-ff-search-library-in-sexp t
        helm-scroll-amount 8 
        helm-echo-input-in-header-line t)
  :init
  (helm-mode 1))

(require 'helm-config)    
(helm-autoresize-mode 1)
(define-key helm-find-files-map (kbd "C-b") 'helm-find-files-up-one-level)
(define-key helm-find-files-map (kbd "C-f") 'helm-execute-persistent-action)

6.14 Programmation

6.14.1 Gestion correcte des mots écrits en camelCase

Les mots écrits en camelCase sont considérés comme des mots distincts. Ainsi "leChat" sera interprété comme "le" "chat" dans les modes de programmation.

(add-hook 'prog-mode-hook 'subword-mode)

6.14.2 folding

Afin de pouvoir plier/déplier des morceaux de code, origami est bien pratique. Son préfixe est C-x C-z (après avoir chargé ce mode mineur).

(use-package origami
  :ensure t
  :demand
  :config
  (define-prefix-command 'origami-mode-map)
  (global-set-key (kbd "C-x C-z") 'origami-mode-map)
  (global-origami-mode)
  :bind
  (:map origami-mode-map
        ("o" . origami-open-node)
        ("O" . origami-open-node-recursively)
        ("c" . origami-close-node)
        ("C" . origami-close-node-recursively)
        ("a" . origami-toggle-node)
        ("A" . origami-recursively-toggle-node)
        ("R" . origami-open-all-nodes)
        ("M" . origami-close-all-nodes)
        ("v" . origami-show-only-node)
        ("k" . origami-previous-fold)
        ("j" . origami-forward-fold)
        ("x" . origami-reset))
  :diminish)

;; Origami mode keys
(define-key global-map (kbd "C-x C-z") 'origami-mode-map)
(define-prefix-command 'origami-mode-map)
(define-key origami-mode-map (kbd "o") 'origami-open-node)
(define-key origami-mode-map (kbd "O") 'origami-open-node-recursively)
(define-key origami-mode-map (kbd "c") 'origami-close-node)
(define-key origami-mode-map (kbd "C") 'origami-close-node-recursively)
(define-key origami-mode-map (kbd "a") 'origami-toggle-node)
(define-key origami-mode-map (kbd "A") 'origami-recursively-toggle-node)
(define-key origami-mode-map (kbd "R") 'origami-open-all-nodes)
(define-key origami-mode-map (kbd "M") 'origami-close-all-nodes)
(define-key origami-mode-map (kbd "v") 'origami-show-only-node)
(define-key origami-mode-map (kbd "k") 'origami-previous-fold)
(define-key origami-mode-map (kbd "j") 'origami-forward-fold)
(define-key origami-mode-map (kbd "x") 'origami-reset)

;; Set up some global minor modes
(global-origami-mode t)
(show-paren-mode t)
(global-prettify-symbols-mode t)

6.14.3 Reformatage automatique

Le reformatage est une version avancée de ce que l'on utilise avec la touche TAB lorsqu'on code. Cela va modifier les espacements, les sauts de lignes, etc… à l'intérieur du code. C'est particulièrement important lorsqu'on travaille à plusieurs car cela donne une certaine unité de style qui permet d'accélérer la lecture de code. Clang propose un reformatage qui peut être paramètré selon les goûts de l'utilisateur de façon assez aisée (c'est un fichier texte assez compréhensible qui définit les règles de reformatage).

Avant de pouvoir utiliser les lignes qui suivent, il est nécessaire

  • d'installer clang-format sous linux
  • définir sous linux votre configuration de formatage. Emacs va faire appel à ce fichier afin d'en utiliser les paramètres. Ce fichier peut se trouver dans la racine du projet, ou à défaut dans votre HOME. Pour le créer on peut utiliser l'une des lignes qui suit selon le style que l'on désire adopter… ou créer soi-même son fichier. Ces styles ont été conçus pour C/C++/Java/JavaScript/Objective-C/Protobuf/C# LLVM, Google, Chromium, Mozilla, WebKit
    • style clang : clang-format -style=llvm -dump-config > .clang-format
    • style Mozilla : clang-format -style=Mozilla -dump-config > .clang-format
    • style Google : clang-format -style=Google -dump-config > .clang-format
    • style Chromium : clang-format -style=Chromium -dump-config > .clang-format
    • style Webkit : clang-format -style=Webkit -dump-config > .clang-format
(use-package clang-format+
  :ensure t)

(add-hook 'c-mode-common-hook #'clang-format+-mode)
(add-hook 'c-mode-common-hook
          (lambda ()
            (local-set-key (kbd "C-x <C-tab>") 'clang-format-region)))

6.14.4 Correction 'à la volée'

Afin que des indications de corrections soient présentes lors de la frappe, on utilise flycheck. Il est utilisé principalement pour le code( c'est spellcheck ).

(use-package flycheck
  :ensure t
  :init
  (global-flycheck-mode t)
  (set-face-attribute 'flycheck-error nil :foreground "black" :background
                      "#EE4400")
  (set-face-attribute 'flycheck-warning nil :foreground "black" :background
                      "#EE9900")
  (set-face-attribute 'flycheck-info nil :foreground "black" :background
                      "#008800")
  :diminish)

6.14.5 c++ / c

(add-hook 'c++-mode-hook 'yas-minor-mode)
(add-hook 'c-mode-hook 'yas-minor-mode)

(use-package flycheck-clang-analyzer
  :ensure t
  :config
  (with-eval-after-load 'flycheck
    (require 'flycheck-clang-analyzer)
     (flycheck-clang-analyzer-setup)))

(with-eval-after-load 'company
  (add-hook 'c++-mode-hook 'company-mode)
  (add-hook 'c-mode-hook 'company-mode))

(use-package company-c-headers
  :ensure t)

(use-package company-irony
  :ensure t
  :config
  (setq company-backends '((company-c-headers
                            company-dabbrev-code
                            company-irony))))

(use-package irony
  :ensure t
  :config
  (add-hook 'c++-mode-hook 'irony-mode)
  (add-hook 'c-mode-hook 'irony-mode)
  (add-hook 'irony-mode-hook 'irony-cdb-autosetup-compile-options))

(use-package ggtags
:ensure t
:config 
(add-hook 'c-mode-common-hook
          (lambda ()
            (when (derived-mode-p 'c-mode 'c++-mode 'java-mode)
              (ggtags-mode 1))))
)

Avec le code qui suit il est possible de replier des fonctions du code, ceci rend la lecture et la navigation dans des codes longs plus agréable. Les contrôles à connaître sont indiqués dans le code. Il existe également un greffon pour réaliser ce travail origami.

(add-hook 'c-mode-common-hook
          (lambda()
            (local-set-key (kbd "M-<right>") 'hs-show-block)
            (local-set-key (kbd "M-<left>")  'hs-hide-block)
            (local-set-key (kbd "M-<up>")    'hs-hide-all)
            (local-set-key (kbd "M-<down>")  'hs-show-all)

            ;;hide/show code-block
            (hs-minor-mode t)))

6.14.6 Lisp like

;; Paredit pour la gestion des parenthéses en lisp
;; setup paredit
(use-package paredit
  :ensure t
  :init
  (dolist (hook '(emacs-lisp-mode-hook lisp-mode-hook clojure-mode-hook scheme-mode-hook))
    (add-hook hook 'paredit-mode))
  :diminish paredit-mode)

6.14.7 Python

(add-hook 'python-mode-hook 'yas-minor-mode)
(add-hook 'python-mode-hook 'flycheck-mode)

(with-eval-after-load 'company
    (add-hook 'python-mode-hook 'company-mode))

(use-package company-jedi
  :ensure t
  :config
    (require 'company)
    (add-to-list 'company-backends 'company-jedi))

(defun python-mode-company-init ()
  (setq-local company-backends '((company-jedi
                                  company-etags
                                  company-dabbrev-code))))

(use-package company-jedi
  :ensure t
  :config
    (require 'company)
    (add-hook 'python-mode-hook 'python-mode-company-init))

(use-package virtualenvwrapper
          :ensure t
          :config
          (venv-initialize-interactive-shells)
          (venv-initialize-eshell))

(setq python-shell-interpreter "python3")
(setq python-shell-interpreter-args "-m IPython --simple-prompt -i") 
(setq flycheck-python-pycompile-executable "python3")

6.14.8 bash

(add-hook 'shell-mode-hook 'yas-minor-mode)
(add-hook 'shell-mode-hook 'flycheck-mode)
(add-hook 'shell-mode-hook 'company-mode)

(defun shell-mode-company-init ()
  (setq-local company-backends '((company-shell
                                  company-shell-env
                                  company-etags
                                  company-dabbrev-code))))

(use-package company-shell
  :ensure t
  :config
    (require 'company)
    (add-hook 'shell-mode-hook 'shell-mode-company-init))
  1. Couleur
    (use-package xterm-color
      :ensure t
      :config
      (setq comint-output-filter-functions
            (remove 'ansi-color-process-output comint-output-filter-functions))
    
      (add-hook 'shell-mode-hook
                (lambda () (add-hook 'comint-preoutput-filter-functions
                                     'xterm-color-filter nil t))))
    

6.14.9 html

  1. Coloration syntaxique pour le langage html.
    (use-package htmlize
      :ensure t)
    
  2. Outils de base pour html
    (use-package web-mode
      :ensure t
      :config
      (add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode))
      (add-to-list 'auto-mode-alist '("\\.vue?\\'" . web-mode))
      (setq web-mode-engines-alist
            '(("django"    . "\\.html\\'")))
      (setq web-mode-ac-sources-alist
            '(("css" . (ac-source-css-property))
              ("vue" . (ac-source-words-in-buffer ac-source-abbrev))
              ("html" . (ac-source-words-in-buffer ac-source-abbrev))))
      (setq web-mode-enable-auto-closing t))
    (setq web-mode-enable-auto-quoting t)
    

6.14.10 CSS

Pour les feuilles de style :

(use-package css-mode
  :ensure t
  :custom (css-indent-offset 2))

(use-package scss-mode
  :ensure t
  :preface
  (defun me/scss-set-comment-style ()
    (setq-local comment-end "")
    (setq-local comment-start "//"))
  :mode ("\\.sass\\'" "\\.scss\\'")
  :hook (scss-mode . me/scss-set-comment-style))

6.14.11 emacs-lisp

(add-hook 'emacs-lisp-mode-hook 'eldoc-mode)
(add-hook 'emacs-lisp-mode-hook 'yas-minor-mode)
(add-hook 'emacs-lisp-mode-hook 'company-mode)

(use-package slime
  :ensure t
  :config
  (setq inferior-lisp-program "/usr/bin/sbcl")
  (setq slime-contribs '(slime-fancy)))

(use-package slime-company
  :ensure t
  :init
    (require 'company)
    (slime-setup '(slime-fancy slime-company)))

6.14.12 gnuplot

Avant de charger ce greffon, il est nécessaire d'avoir préalablement installé sous linux gnuplot. Ce package permet d'avoir accès au mode majeur gnuplot d'une part, et d'autre part, une fois org-babel configuré, de pouvoir utiliser gnuplot à l'intérieur des fichiers en orgmode.

Il est possible que maintenant que des modules tels que seaborn existent en Python, il devienne obsolète… Je ne me suis pas encore fait mon idée personnelle sur ce sujet, mais il est possible que je l'abandonne d'ici peu (Python et ses modules doivent être compatibles avec orgmode).

(use-package gnuplot
  :ensure t)

6.14.13 GraphViz

Jusqu'à ce que python devienne si agréable pour les représentations de graphe avec des modules comme networkx, graphViz a longtemps tenu (et tient encore souvent) une place prépondérante. Il est facile à utiliser, et possède pour les cas standards une syntaxe agréable. Il possède des interfaces pour de multiples langages que ce soit du C ou du Python, ou… C'est un outil dont il est bon de connaître au moins les bases.

Il est nécessaire d'installer GraphViz sans le système avant de pouvoir l'utiliser (on en a également besoin pour Doxygen et pour quelques autres logiciels).

Documentations:

(use-package graphviz-dot-mode
  :ensure t)
(use-package company-graphviz-dot)

6.14.14 Ditaa

Ditaa permet de transformer un graphique fait en ASCII en un 'vrai' graphique. L’exemple de la page de ce projet est suffisamment parlant :

+--------+   +-------+    +-------+
|        | --+ ditaa +--> |       |
|  Text  |   +-------+    |diagram|
|Document|   |!magic!|    |       |
|     {d}|   |       |    |       |
+---+----+   +-------+    +-------+
    :                         ^
    |       Lots of work      |
    +-------------------------+

se transformera en :

test_ditaa.png

Ditaa nécessite d'être installé sur le système préalablement à son utilisation sous emacs (il est présent sur la plupart des dépots pour toutes les distributions je pense).

NB : Il faut penser à modifier le chemin d'accès de ditaa qui, en tous cas sur le système sur lequel je suis aujourd'hui, n'est pas le bon:

(setq org-ditaa-jar-path "/usr/bin/ditaa")

6.14.15 Markdown

Un mode majeur pour le markdown, le rendu étant réalisé sur le navigateur.

(use-package markdown-mode
  :ensure
  :preface
  (defun my/markdown-set-ongoing-hydra-body ()
    (setq my/ongoing-hydra-body #'hydra-markdown/body))
  :mode
  ("INSTALL\\'"
   "CONTRIBUTORS\\'"
   "LICENSE\\'"
   "README\\'"
   "\\.markdown\\'"
   "\\.md\\'")
  :hook
  (markdown-mode . my/markdown-set-ongoing-hydra-body)
  :custom
  (markdown-asymmetric-header t)
  (markdown-split-window-direction 'right)
  :config
  (unbind-key "M-<down>" markdown-mode-map)
  (unbind-key "M-<up>" markdown-mode-map))

6.14.16 Bison lex yacc flex

  • Lex (et sa variation flex) est un outil pour réaliser un scanner (tokenizer) utile pour la première phase d'une compilation. La fonction du scanner est de découper un code source en tokens (ceci_est_un_entier, ceci_est_le_mot_clef_if, ceci_est_une_variable, etc.).
  • yacc (et sa variation bison) est un outil pour réaliser le parsing, deuxième phase de la compilation. Le parseur récupère les tokens fournis par le parseur, vérifie qu'ils s'agencent correctement selon la syntaxe du langage, et produit une action associée aux phrases syntaxiquement correctes.
;;  (use-package bison-mode :ensure t)
;; (require 'flex)
;;
;; (add-to-list 'auto-mode-alist '("\\.l$" . flex-mode))
;; (autoload 'flex-mode "flex")

6.15 The artist

Afin que ce mode fonctionne bien, il ne faut pas qu'il y ait de modifications des tabulations.

(add-hook 'artist-mode-hook (lambda () (setq indent-tabs-mode nil)))

6.16 Git

Magit est le greffon usuel pour ce qui est de Git. Il permet d'obtenir une interface pour git, plus agréable que la ligne de commande.

Deux liens pour bien comprendre l'utilisation de magit :

(use-package magit
  :ensure t
  :init
  (progn
    (bind-key "C-x g" 'magit-status)
    ))

(setq magit-status-margin
      '(t "%Y-%m-%d %H:%M " magit-log-margin-width t 18))

git-gutter permet d'observer les modifications directement dans un fichier durant l'édition par des symboles placés en début de ligne. Il permet également d'agir sur chaque modification indépendamment des autres (un peu comme le mode correction de word)

(use-package git-gutter
  :ensure t
  :init
  (global-git-gutter-mode +1))

(global-set-key (kbd "M-g M-g") 'hydra-git-gutter/body)

Git-timemachine permet de se déplacer aisément à l'intérieur des anciens commit.

(use-package git-timemachine
  :ensure t
  )

La configuration pour git de hydra (raccourcis de commandes pour la famille).

(defhydra hydra-git-gutter (:body-pre (git-gutter-mode 1)
                                      :hint nil)
  "
  Git gutter:
    _j_: next hunk        _s_tage hunk     _q_uit
    _k_: previous hunk    _r_evert hunk    _Q_uit and deactivate git-gutter
    ^ ^                   _p_opup hunk
    _h_: first hunk
    _l_: last hunk        set start _R_evision
  "
  ("j" git-gutter:next-hunk)
  ("k" git-gutter:previous-hunk)
  ("h" (progn (goto-char (point-min))
              (git-gutter:next-hunk 1)))
  ("l" (progn (goto-char (point-min))
              (git-gutter:previous-hunk 1)))
  ("s" git-gutter:stage-hunk)
  ("r" git-gutter:revert-hunk)
  ("p" git-gutter:popup-hunk)
  ("R" git-gutter:set-start-revision)
  ("q" nil :color blue)
  ("Q" (progn (git-gutter-mode -1)
              ;; git-gutter-fringe doesn't seem to
              ;; clear the markup right away
              (sit-for 0.1)
              (git-gutter:clear))
   :color blue))

6.17 Mails

Une fois que l'on a gouté à emacs et qu'on commence à bien le maitriser, on a envie de l'utiliser, en particulier lorsqu'il s'agit de manipuler du texte. Les deux solutions les plus classiques sont mu4e et gnus pour la gestion des emails. Tous les deux fonctionnent bien, mais ils ont tendance à nécessiter une configuration assez pointilleuse. Une explication est proposée ici pour mu4e et il en existe de nombreuses autres sur le net pour gnus.

6.18 Gadgets

6.18.1 Météo M-x wttrin

On peut modifier la localisation, en mettre plusieurs,… Pour y accéder M-x wttrin

(use-package wttrin
  :ensure t
  :commands (wttrin)
  :init
  (setq wttrin-default-cities '("Aydat" "Clermont-Ferrand" "Hanoi")))

6.18.2 Musique

Il existe un greffon pour spotify, et des greffons pour la musique en local : Bongo et emms.

6.18.3 Processus

Le but est d'observer les processus et obtenir un résultat similaire à la commande top sous linux. Les contrôles clavier par défaut utilisent la touche 'Super' (windows sur la plupart de nos claviers) et nécessiteraient donc de 'remapper' les touches. Personnellement, je l'utilise avec les menus :).

Pour l'exécuter M-x proced.

(use-package proced
:commands proced
:config
(setq proced-auto-update-flag t)
(setq proced-auto-update-interval 1)
(setq proced-descend t)
(setq proced-filter 'user))

6.18.4 Golf

Des exercices pour apprendre à utiliser emacs, à la façon de vimgolf. Pour obtenir le numéro du challenge, sur le site vimgolf lorsqu'on clique sur un défi, son 'numéro' est la chaîne de carctères qui termine l'adresse (par exemple : 5e4dfcccaa2db400090b66c3). La configuration clavier est la suivante :

C-c C-v C-c
vimgolf-submit
C-c C-v r
vimgolf-revert
C-c C-v d
vimgolf-diff
C-c C-v c
vimgolf-continue
C-c C-v p
vimgolf-pause
C-c C-v q
vimgolf-quit
(use-package vimgolf
  :ensure t)

6.18.5 Epub

Lire des romans sous emacs.

(use-package nov
  :ensure t
  :mode ("\\.epub\\'" . nov-mode)
  :config (progn
            (defun my-nov-font-setup ()
              (face-remap-add-relative 'variable-pitch
                                       :family "Gentium Book Basic"
                                       :height 1.0))
            (add-hook 'nov-mode-hook 'my-nov-font-setup)

            (setq nov-text-width 80)

            (defun my-nov-window-configuration-change-hook ()
              (my-nov-post-html-render-hook)
              (remove-hook 'window-configuration-change-hook
                           'my-nov-window-configuration-change-hook
                           t))

            (defun my-nov-post-html-render-hook ()
              (if (get-buffer-window)
                  (let ((max-width (pj-line-width))
                        buffer-read-only)
                    (save-excursion
                      (goto-char (point-min))
                      (while (not (eobp))
                        (when (not (looking-at "^[[:space:]]*$"))
                          (goto-char (line-end-position))
                          (when (> (shr-pixel-column) max-width)
                            (goto-char (line-beginning-position))
                            ))
                        (forward-line 1))))

                (add-hook 'window-configuration-change-hook
                          'my-nov-window-configuration-change-hook
                          nil t)))

            (add-hook 'nov-post-html-render-hook 'my-nov-post-html-render-hook)))

7 Org : remplacer Excel ?

Les tables en orgmode sont très puissantes, elles permettent de présenter des données texte et image. Elles disposent d'importantes fonctions de manipulation et de calcul. Il est également possible de créer des représentation graphiques en couplant ces tables à gnuplot, ou à un quelconque autre logiciel produisant aisément des graphiques.

Non, tout comme on ne jettera pas \(\LaTeX\) au profit d'orgmode (mais on pourra les coupler, cela se fait très bien), on ne va pas jeter les tableurs à la poubelle, ils ont un confort d'utilisation qui n'est pas comparable avec ce que propose orgmode, et ils sont nettement plus aptes à traiter des feuilles de données contenant une multitude de calculs différents. En revanche, là où orgmode est certainement plus efficace, c'est dans ses interactions avec du code informatique, où il a une puissance et un confort d'utilisation indéniables.

7.1 Créer une table 'à la main'

Pour taper l'exemple qui suit, la touche TAB permet de créer une ligne dès que les premiers caractères ont été tappés (soit|, soit |-).

| Colonne 1 | Colonne 2 |             Colonne3 |
|-----------+-----------+----------------------|
|    <c>    | <l>       |                  <r> |
|-----------+-----------+----------------------|
|  orgmode  | est       | vraiment fantastique |
|  orgmode  | est       |   réellement magique |
|-----------+-----------+----------------------|

7.2 Nommer

C'est une bonne idée de nommer la table, on pourra alors y faire référence dans la suite du document. Cela se fait par la commande #+tblname: NomDeMaTable placée juste avant la table.

7.3 Récupération de données

Pour créer une table, on peut également récupérer des données et les transformer en table. Suivre la séquence suivante :

  1. se placer (dans une fenêtre shell) dans un répertoire qui contient une dizaine de fichiers
  2. lister le contenu du répertoire ls -l
  3. sélectionner (à la souris) le résultat dans le shell et le copier dans emacs dans un fichier .org
  4. sélectionner votre 'collé'
  5. le transformer en table C-c | Voici un exemple de résultat:

    | -rw-r--r-- | 1 | sandman | sandman | 196492 | mars  | 24 | 17:44 | Ah-Finally.jpg       |
    | -rw-r--r-- | 1 | sandman | sandman |  18285 | mars  | 25 | 00:29 | emacs_fingers.jpg    |
    | -rw-r--r-- | 1 | sandman | sandman | 269778 | mars  | 24 | 17:14 | emacs_octopus.jpg    |
    | -rw-r--r-- | 1 | sandman | sandman |  76110 | mars  | 24 | 17:44 | emacs_os.jpg         |
    | -rw-r--r-- | 1 | sandman | sandman | 115251 | mars  | 30 | 11:11 | Emacs_refcard.pdf    |
    | -rw-r--r-- | 1 | sandman | sandman |  84999 | mars  | 25 | 00:28 | emacs_vim.jpg        |
    | -rw-r--r-- | 1 | sandman | sandman |  82248 | avril |  6 | 14:03 | emacs_vi_nano.jpg    |
    | -rw-r--r-- | 1 | sandman | sandman | 112499 | avril |  6 | 14:26 | Jupyter_logo.jpg     |
    | -rw-r--r-- | 1 | sandman | sandman |  11002 | avril |  6 | 14:19 | logo_jupyter.svg     |
    | -rw-r--r-- | 1 | sandman | sandman | 120891 | mars  | 30 | 01:08 | orgcard.pdf          |
    | -rw-r--r-- | 1 | sandman | sandman |  13306 | avril |  5 | 12:15 | org_licorne.jpg      |
    
  6. ajouter des titres, des barres horizontales, du centrage, …
  7. déplacer des lignes et des colonnes à l'aide de C-ARROW en essayant les différentes directions
  8. supprimer des colonnes à l'aide de M-S-LEFT, en jouter avec M-S-RIGHT
  9. trier les noms des fichiers par ordre alphabetique décroissant C-c ^ puis faire le bon choix [pour le ^ il faut taper ~^ ESP~]

    Voici un résultat à partir de la table précédente :

    #+tblname: imagesDossierOrg
           |-------------------+-------------------------------------+--------+-------|
           | <l>               | <l>                                 |    <r> | <c>   |
           | Nom               | Commentaire                         | Taille | Mois  |
           |-------------------+-------------------------------------+--------+-------|
           | org_licorne.jpg   | ma fille aussi l'aime bien          |  13306 | avril |
           | orgcard.pdf       | je n'ai aucune mémoire              | 120891 | mars  |
           | Jupyter_logo.jpg  | pour python                         | 112499 | avril |
           | emacs_vi_nano.jpg | j'ai choisi Emacs                   |  82248 | avril |
           | emacs_vim.jpg     | no comment                          |  84999 | mars  |
           | emacs_refcard.pdf | nécessaire pour les poissons rouges | 115251 | mars  |
           | emacs_os.jpg      | terrible                            |  76110 | mars  |
           | emacs_octopus.jpg | ce n'est ps vrai                    | 269778 | mars  |
           | emacs_fingers.jpg | belle mutation                      |  18285 | mars  |
           | Ah-Finally.jpg    | cela peut prendre un peu de temps   | 196492 | mars  |
           |-------------------+-------------------------------------+--------+-------|
    

7.4 Calculer

  1. Avant de calculer, on va afficher les numéros de lignes et de colonnes de la table C-c }. Les traits horizontaux sont référencées par I*1, I*2, … les lignes entre deux horizontales par 1, 2,.. et les colonnes par $1, $2, …
  2. Pour référencer une cellule
    • référence absolue :
      • @2$3 ligne 2, colonne 3
      • @2 ligne 2 (même colonne)
      • $3 colonne 3 (même ligne)
      • @> dernière ligne
    • référence relative
      • @+1 ligne suivante
      • @-2 deux lignes avant
      • $+1 colonne suivante (même ligne)
      • $-2 deux colonnes après (même ligne)
  3. Pour référencer une plage (range en anglais), coin_supérieur_gauche .. coin_inférieur_
  4. Pour coller une formule dans une cellule C-c *
  5. Pour coller une formule dans toutes les lignes d'une colonne C-u C-c *
  6. Pour taper une formule
    • Pour unce cellule unique :=formule, par exemple :=@3$2+vmean(@3..@12)
    • Pour une colonne =formule, par exemple =$1+$2*3
    • Pour pouvoir travailler sur toute la table C-c ' et pour sauvegarder C-x C-s
    • Pour exécuter le calcul C-c C-c sur la ligne #+TBLFM: ... qui est par ailleurs directement éditable
  7. Table des fonctions mathématiques élémentaires
Fonction Description
exp(c) exponentelle
log(c) logarithme néperien
log10(c) log base 10
sqrt(c) racine carrée
vmin(v) minimum
vmax(v) maximum
vmean(v) moyenne
vmedian(v) mediane
vsdev(v) écart type
vvar(v) variance
vcov(v1, v2) covariance de deux vecteurs
vcor(v1, v2) coefficient de corrélation de deux vecteurs
sin, cos, tan trigonométrie
taylor(v1, x=0,2) développement de taylor en 0 à l'ordre 2
if(boolean, result_if_true, result_if_false) Si, alors, sinon
 

En fait, il existe même des fonctions de recherche, … mais il existe peut-être des logiciels plus conviviaux si on a besoin d'un tableur pour réaliser des feuilles de calcul complexes.

7.5 Représenter avec gnuplot

7.5.1 Avant de commencer

Il arrive que votre document semble parfait… et que rien ne fonctionne comme prévu. Une des causes possible est la présence d'espaces à la fin d'une ou plusieurs de vos commandes. Certains espaces posent problème, d'autres non…

Si on désire exécuter un bloc de code, on place le curseur en son sein, et C-c C-c. Pour afficher les graphiques à l'intérieur de votre document orgmode, C-c C-x C-v ou (org-toggle-inline-images).

Pour continuer une commande tout en allant à la ligne, on utilise \, cela est très utilisé car de nombreuses commandes sont très longues car elles comprennent de nombreux modificateurs.

7.5.2 Documentation

  • Un document basique pour orgmode Org-babel-gnuplot, pour savoir comment accéder aux données depuis orgmode
  • Un document agréable sur gnuplot Introduction to gnuplot, pour savoir comment utiliser les données afin de réaliser les graphiques de son choix. Attention, il parle de l’utilisation en ligne de commande (qui est un mode majeur que vous pouvez activer par M-x gnuplot-mode), et il y a donc quelques différences avec son utilisation en orgmode.
  • Un cours sur gnuplot cours de Bernard Desgraupe.

7.5.3 Un exemple

Il est possible de récupérer les données d'une table pour les afficher avec gnuplot. Voici un exemple d'histogramme que l'on peut adapter et compléter.

  1. Création des données

    On commence par créer une table sur de goûts musicaux imaginaires, que l'on nomme par #+tblname: musique

    Groupe Avis Alice Avis Bob
    Pigale 5 9
    Volo 6 7
    L. Cohen 10 10
    P. Glass 8 5
    J. McLaughin 3 8
    Cat Stevens 8 2
    Brassens 8 10
    Ferré 10 9
    Stromae 5 6
    L. McKennitt 9 8
    Faun 3 6
    A. HK 5 8
    A. Miller 8 7
    G. Yacoub 10 5
  2. Une représentation par histogramme
    Org/gnuplot code Signification
    #+begin_src gnuplot :var data=musique :results output :file ./img/goutsMusique.png Source gnuplot, les données sont dans la table 'musique', générer le fichier xxx.png
    set terminal png size 800,350 Taille en pixel de l'image
    set title "Avis Musique" Titre au graphique
    set xlabel "Groupe" Etiquette de l'axe des abscisses
    set ylabel "Avis" Etiquette de l'axe des ordonnées
    set xtics rotate by -45 Les étiquettes de l'axe des abscisses sont tournées de 45°
    set yrange[0:10] Etendue des ordonnées
    set style data histogram Le graphique sera un histogramme
    set style fill solid \ Les rectangles de l'histogramme sont coloriés
    border 3 La bordure des rectangles est de type 3
    set key outside bottom La légende est à l'extérieur de l'histogramme, en dessous
    plot data using 2:xticlabels(1) title 'Alice', \ Dessiner les données, la première série s'appelle 'Alice', les valeurs sont dans la colonne 2, et leurs noms en colonne 1
    data using 3:xticlabels(1) title 'Bob' la deuxième série s'appelle 'Bob', les valeurs sont dans la colonne 3, et leurs noms en colonne 1
    #+end_src Fin du code

    goutsMusique.png

  3. Une représentation en x,y (scatterplot)
    Org/gnuplot code Signification
    #+begin_src gnuplot :var data=musique :results output :file./img/relationGouts.png Source gnuplot, les données sont dans la table 'musique', générer le fichier xxx.png
    set terminal png size 500,500 Taille en pixel de l'image
    set title "Correlation des gouts" Titre au graphique
    set xlabel "Alice" Etiquette de l'axe des abscisses
    set ylabel "Bob" Etiquette de l'axe des ordonnées
    set xrange[0:11] Etendue des abscisses
    set yrange[0:11] Etendue des ordonnées
    plot data using 2:3:(sprintf("%s (%d, %d)",stringcolumn(1), $2, $3)) with\ Représenter les données avec les x dans la colonne 2, les y en colonne 3, et une étiquette calculée
    labels\ Les points sont étiquetés
    point pt 5\ Les points sont marqué par le symbole référencé 5
    offset char 0,-1\ Les étiquettes sont décalées de 0 caractère en abscisse, -1 caractère en ordonnées
    font "Times,7"\ La police des étiquettes est Times, taille 7
    notitle Pas de légende aux séries
    #+end_src Fin source gnuplot

    relationGouts.png

8 Org : remplacer jupyter ?

8.1 Présentation

D. Knuth a défini ce qu'on appelle le 'Literate Programming'. Cela consiste à mixer des fragments de code avec les explications des principes qui les sous-tendent.

Le domaine de la programmation lettrée s'est depuis quelques années étendu, pour donner lieu à la recherche reproductible qui a ajouté à son objectif premier (l'explication) l'idée que l'origine des résultats obtenus au cours de recherches doit pouvoir être tracée. Il ne suffit pas d'annoncer un résultat 'la dépense en sciences, espace et technologie est corrélée à 99,79% avec le nombre de suicides par pendaison, strangulation et suffocation', il faut exposer la provenance des sources, et présenter la suite des opérations qui ont permis d'obtenir cette conclusion. (Pour info la source ici est sérieuse, et je l'utilise en cours de statistiques et fouille de données pour expliquer que corrélation n'est pas causalité.)

Si une recherche n'est pas reproductible, elle perd une partie de sa pertinence, et dans la plupart des cas elle quitte le domaine scientifique pour devenir une croyance. Il peut arriver que la collecte des données soit difficilement reproductible parce que… les phénomènes ne se reproduisent pas (recherche historique, psychologie, éthologie, écologie, …), ou simplement à cause de coûts prohibitifs (mesure de cosmologie, hautes énergies,…), mais le traitement des données est, lui, reproductible, et il est responsable de bien des erreurs (les statistiques mal utilisées, sans même être malhonnête : paradoxe de Simpson par exemple, et si à cela on ajoute de la manipulation volontaire…).

disraeli.jpg

Figure 11 : Certains attribuent cette citation à M. Twain

Au départ, il existait des outils spécialisés afin de mettre en œuvre ce mélange d’explications et de code/calculs, et maintenant, les deux applications qui me semblent les plus pertinentes sont :

  • les Jupyter notebooks, très à la mode, simples d'accès, souvent sans installation, à connaître (mais ne font pas l'objet de ce cours)
  • orgmode, plus polyvalent, plus puissant, extensible… nécessitant un apprentissage et une configuration (si on a déjà appris emacs, les choses ne sont pas si terribles, à condition d'y aller à petits pas).

8.2 Insérer du code exécutable

Pour insérer du code exécutable on insère du code placé entre les balises #+begin_src langage et #+end_src (attention, ces balises doivent être placées en 'début' de ligne, c'est à dire uniquement précédées d'espaces). Entre les balises, on écrit normalement le code. Cela donne le squelette:

>  #+NAME: <name>
>  #+BEGIN_SRC <language> <switches> <header arguments>
>    <body>
>  #+END_SRC

Bruegel_the_Elder.jpg

Figure 12 : Tour de Babel, Bruegel l'ancien

La liste des langages disponible ainsi que les noms à utiliser dans la déclaration du bloc de code dépendent des fonctions invoquées lors du chargement de 'babel' (ne pas rater pas ce lien… sans en faire une crise métaphysique, même si vous apprenez que 'yves jean died tonight, eaten by a whale from outer space' (mur 1, étagère 3, volume 31, page 296)).

babel-fish.jpg

Figure 13 : “The poor Babel fish, by effectively removing all barriers to communication between different cultures and races, has caused more and bloodier wars than anything else in the history of creation.” D. Adams, The Hitchiker's Guide to the Galaxy

Si on désire dans l'instant avoir une évaluation du bloc C-c C-c lorsque le curseur est positionné à l'intérieur du bloc.

Le fichier de configuration d'emacs tel qu'il est présenté ici est ainsi un mélange de texte et de code emacs-lisp.

Astuces et commentaires :

  • Pour commencer un bloc de code <s TAB et compléter par le nom du langage, les options, …
  • On peut éditer un bloc de code en utilisant tous les outils adaptés, comme par exemple flycheck
    • C-c ' permet d'ouvrir le code dans un nouveau buffer
    • que l'on peut sauvegarder dans le buffer d'origine par également C-c '
    • ou annuler les modifications par C-c C-k
  • Le C n'est pas le langage le plus adapté pour ce type de document, les langages fonctionnels ou les langages interprétés s'adaptent plus facilement.

8.2.1 Les paramètres

Le nombre de paramètre utilisés peut rapidement devenir assez important, et il peut devenir difficile de les manipuler aisément (on précise la forme des entrées, des résultats, les répertoires, …). Il peut alors être pratique de définir des paramètres de façon plus flexible.

Les différentes méthodes sont :

  1. définir les paramètres pour une section (et ses sous sections), pour cela on utilise un tiroir comme dans cet exemple, que l'on place juste après le titre de la section. Dans l'exemple qui suit, pour tout le sous arbre débutant à ce point, la variable dir vaudra /etc.

    :PROPERTIES:
    :header-args: :dir /etc
    :END:
    
  2. définir les paramètres juste avant la définition du code. Dans l’exemple qui suit, la variable dir vaut /bin juste pour le code qui suit

    #+header: :dir /bin
    #+BEGIN_SRC sh
      ls
      ...
    
  3. définir les paramètres selon le squelette de base.

On peut noter que les méthodes 2 et 3 prennent le pas sur la méthode 1, qui constitue une définition de paramètres par défaut.

8.2.2 Affichages : documentation

Ce qui sera affiché comme résultat au programme, ainsi que la forme du résultat affiché (ou exporté) peuvent être précisés par les options que l'on précise après la balise results::

  • Ce qui sera affiché
    value
    option par défaut, renvoie les affichages du code (prints en tous genre, et pour les fonctions, la valeur du return ou équivalent)
    output
    renvoie les éléments sur le flux de sortie standard (et plus le résultat de la dernière fonction)
  • Apparence de l'affichage, formatage
    table
    option par défaut, renvoie les résultats sous la forme d'un tableau orgmode (l'option hline: avec yes ou no permet d'afficher ou non des lignes)
    list
    renvoie une liste orgmode
    verbatim
    renvoie les résultats sous forme de citation
    file
    renvoie le résultat dans le fichier dont le nom est donné ensuite, on peut préciser le noim d'un répertoire de base par output-dir: suivi d'un nom de répertoire (il existe d'autres nuances possibles, Cf. documentation)
  • Format d'encapsulation, par défaut le résultat est dans un bloc orgmode, mais on peut l'insérer dans un autre type de bloc
    code
    produit un bloc de code
    drawer
    produit un tiroir (une encapsulation)
    html
    produit du code html
    latex
    produit du code \(\LaTeX\)
    (no term)
  • Cumul des sorties, par défaut les nouvelles sorties remplacent les anciennes, les deux dernières options permettent de conserver les résultats des différentes exécutions du code
    silent
    la sortie ne se fait pas dans le buffer mais dans le mini-buffer
    replace
    option par défaut
    append
    met la nouvelle sortie après les précédentes
    prepend
    met la bouvelle sortie avant les précédentes

Exemples

  • #+BEGIN_SRC C :results table :file toto.txt :output-dir ./img/

produit un fichier texte dans le répertoire indiqué qui contient les résultats du code

  • #+BEGIN_SRC C :results table html produit le résultat sous la forme d'une table orgmode, encapsulée dans des balises délimitant du code html

8.2.3 Exports

Avec :exports on peut choisir les options suivantes :

none
pour désactiver tout export,
code
seul le code sera exporté,
result
seul les résultats produits par l'exécution seront exportés,
both
les deux seront affichés.

Par exemple, avec l'entête #+BEGIN_SRC C :exports both le code suivant affichera à la fois le code et le résultat du code (exactement ce que l'on voit…) après une exportation (en html, …).

#include <stdio.h>
int main(){
  puts("Hello multiverse");
  return 0;
}
Hello multiverse

8.2.4 Appeler une fonction

Pour appeler un code à un autre endroit que là où il a été écrit, on commence par le nommer puis on peut l'invoquer par #+call: nom(paramètres). Par exemple le code suivant commence par définir une fonction qui s'appellera en orgmode toto, qui si on l'exécute affiche un nombre aléatoire dans le mini-buffer (à cause du silent)

#+name: toto
#+BEGIN_SRC C :results silent
  #include <stdio.h>
  #include <stdlib.h>
  #include <time.h>

  int main(){
    srand(time(NULL));
    printf("%d", rand()%100);
    return 0;
  }

On peut alors l'invoquer, si on le désire en modifiant les options d'orgmode (ici on a modifié la sortie pour qu'elle s'affiche dans le fichier orgmode, et que chaque appel ajoute la nouvelle sortie à la précédente).

#+call: toto() :results table append

Pour utiliser des paramètres, on définit des sortes de variables globales dans le bloc de déclaration du code avec le mot clef :var, et on précise une valeur par défaut de ces variables globales. Par exemple, le code suivant possède deux entrées avec leurs valeurs par défaut:

#+name: ex1_code 
#+header: :var data1="Thanks" 
#+header: :var data2="for all the fish"
#+begin_src C 
  #include <stdio.h>

  int main(){
    printf("%s %s\n",data1, data2);
    return 0;
  }
$ $#+end_src

Lors de l'appel on peut redéfinir ces valeurs (le nommage des variables n'est pas obligatoire mais conseillé):

#+call: ex1_code(data1="So", data2="long")

Il est également possible de typer les entrées, de réaliser des post-traitements sur les sorties, etc…

8.2.5 Gestion des entrées

Les entrée peuvent être définies en récupérant des données déjà produites par un autre bloc.

Récupération de données nommées

Dans cet exemple, les données sont dans une table, et le programme C doit les afficher

#+name: ex1_data
 | Le     |
 | Cheval |

En utilisant le programme défini précédemment, on peut l'utiliser sur cette table nommée :

#+call: ex1_code(data1=ex1_data[0,0], data2=ex1_data[1,0])

Pour travailler directement sur des tables, on construit une table que l'on nomme, par exemple :

#+name: ex2_data
| Le    | cheval |     |
| blanc | de     | Bob |

Le code suivant va afficher le contenu d'une table. Il est à noter l'apparition de deux nouvelles variables qui sont créées automatiquement et qui contiennent le nombre de lignes et le nombre de colonnes de la table fournie en entrée.

NB : Après le code la sortie a été nommée, ce qui permettra de la réutiliser ultérieurement.

#+name: ex2_code 
#+header: :var data=ex1_data
#+header: :results raw
#+begin_src C 
  #include <stdio.h>

  int main(){
    for(int i = data_rows-1 ; i>=0 ; --i){
      for(int j = data_cols-1 ; j>=0 ; --j){
        printf("|\ %s ",data[i][j]);
      }
      printf("\n");
    }
    return 0;
  }
$ $#+end_src
#+name: hello

On peut maintenant appeler la fonction et nommer la nouvelle sortie :

#+call: ex2_code(data=ex2_data)
#+name: out

Et on peut utiliser un dés résultats précédents :

#+call: ex2_code(data=out)

9 Babel un peu plus en détail

Cette introduction ne remplace évidemment pas la documentation. Il y a beaucoup d'autres options et façons de travailler, à vous de trouver celle qui vous convient le mieux.

9.1 Configuration

9.1.1 A ajouter à la config emacs

Pour recharger automatiquement les images d'un document orgmode.

(eval-after-load 'org
  (add-hook 'org-babel-after-execute-hook 'org-redisplay-inline-images))

9.1.2 Pour afficher les images à l'ouverture du .org

#+STARTUP: inlineimages  

9.2 Premiers codes

9.2.1 Python

  1. Un premier code
    import random
    
    def generePermutationListe(L, p = None):
        n = len(L)
        if p == None:
            p = n
        out = list(L)
        for i in range(p):
            k = random.randint(i,n-1)
            out[i], out[k] = out[k], out[i]
        return out[:p]
    
    def generePermutationChaine(ch, p = None):
        return "".join(generePermutationListe(list(ch), p))
    
    
    LLE
    

    Il est noté que la valeur de retour définie par une fonction est particulièrement agréable, mais n'est pas disponible pour tous les langages (en particulier, pas pour le c, c++, …)

9.2.2 Graphviz

Pour débuter : http://magjac.com/graphviz-visual-editor/

  strict digraph {
    a [shape="ellipse" style="filled" fillcolor="#1f77b4"]
    b [shape="polygon" style="filled" fillcolor="#ff7f0e"]
    a -> b [fillcolor="#a6cee3" color="#1f78b4"]
    Père [ shape=ellipse style="filled" fillcolor="#FF44cc"]
    Mère [ shape=octagon]
    Frère [ style="radial, solid" color="#c22727" fillcolor="#99cb0b" shape=ellipse]
    Père -> b
    Frère -> Père
    n6
    n6 -> a

    Frère -> b [ style=dashed color="#824848" fillcolor="#a361bb"]
    n6 -> n6 [ style=dashed color="#824848" fillcolor="#a361bb"]
    a -> n6 [ style="tapered, solid" color="#824848" fillcolor="#a361bb"]
    n6 -> Mère [ style="dashed"]
    Mère -> Père
    Frère -> Pierre
    n6 -> Frère
}

graph1.png

9.2.3 Ditaa

Manuel : http://ditaa.sourceforge.net/#usage

/------------------------------\      +-------------------+
|                              |      |  {d}       cGRE   |
|                              |      |                   |
|                              |      | Help   +--------+ |
|        Hello world           +----->|        |  cYEL  | |
|                              |      |        +--------+ |
|                 cBLU         |      +----------+--------+
|                              |        |        |  
\-------------+----------------/        *----+   |  
              ^                         |    |   |  
              |                         v    +-->*--+  
              |                       +---+---+     |
              |                       | {s}   |     |
              v                       | cPNK  +-----+   
+-------------+-----------------+     | Me... |
|  {io}                         |     +---+---+   /--\
|                     cRED      |         |       |  | 
|          Patatoes             +<-----+  :   /---*  *---\
|                               |      |  |   |          +
|                               |      |  |   ++         |
+-------------------------------+      +--+    \---------+

ditaa1.png

9.2.4 C

  1. Un exemple basique
    #include "stdio.h"
    #include "stdlib.h"
    #include "string.h"
    
    int find(char c, char dico[], int len_dico){
      int i = 0;
      char found = 0;
    
      for (i = 0 ; i < len_dico && !found; ++i){
        if (dico[i] == c){
          found= 1;
        }
      }
      if (found){
        return i-1;
      } else{
        return -1;
      }
    }
    
    void counting(char *s, char dico[], int len_dico, int counts[]){
      int pos;
      while (*s){
        pos = find(*s, dico, len_dico);
        if (pos != -1){
          counts[pos]++;
        }
        s++;
      }
    }
    
    void print_counts(char dico[], int len_dico, int counts[]){
      int i;
      for (i = 0 ; i < len_dico; ++i){
        if (dico[i] !=' '){
          printf("%c  %d\n", dico[i], counts[i]);
        } else {
          printf("SPC  %d\n",  counts[i]);
        }
      }
    }
    
    int main(int argc, char** argv){
      (void) argc;
      (void) argv;
    
      char *my_string = "HELLO MY FRIEND";
      char dico[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ";
      int len_dico = strlen(dico);
      int *counts = calloc(len_dico,  sizeof *counts);
    
      counting(my_string,dico, len_dico, counts);
      print_counts(dico, len_dico, counts);
      free(counts);
      return 0;
    }
    
    A 0
    B 0
    C 0
    D 1
    E 2
    F 1
    G 0
    H 1
    I 1
    J 0
    K 0
    L 2
    M 1
    N 1
    O 1
    P 0
    Q 0
    R 1
    S 0
    T 0
    U 0
    V 0
    W 0
    X 0
    Y 1
    Z 0
    SPC 2
  2. Directives de compilation, ligne de commande

    On peut préciser des options de compilation via :flags. Il est ainsi possible de faire appel à des bibliothèques (maths, sdl, …)

     #+BEGIN_SRC C :flags -Wall -Wextra 
    ......
     #+end_src
    

    On peut également préciser des paramètres d'entrée du programme (ce que l'on mettrait sur la ligne de commande lors de l'exécution après le nom de l'exécutable)

    #+BEGIN_SRC C :flags -Wall -Wextra :cmdline <input.txt
    ......
     #+end_src
    

9.3 Graphiques

Créer des graphiques en python est très fréquent car c'est un langage qui dispose de nombreuses bibliothèques très agréables pour manipuler des données (en particulier pandas), et pour réaliser des graphiques (en particulier seaborn).

La méthode (indépendante du langage) est simple, il suffit que le code génère un fichier image, que l'on insère ensuite comme lien là où on désire l'afficher. Afin qu'une nouvelle exécution du code mette à jour l'image affichée, il est utile d'insérer dans le fichier de config d'emacs le code proposé dans la partie 9.1.

import seaborn as sns
import matplotlib.pyplot as plt
import math
import numpy as np
import random


def f(x):
    return math.sin(math.sqrt(7)*x)*x * math.sin(80*x)


def courbe():
    x = list(np.linspace(0,5,1000))
    y = map(f, x)
    y = list(y)
    sns.lineplot(x=x, y=y)

im = np.zeros((10,10), dtype=np.uint8)
for l in range(10):
    for c in range(10):
      im[l, c] = random.randint(0,255)
plt.clf()
plt.imshow(im)
plt.savefig('test2.png')

plt.clf()
courbe()
plt.savefig('test1.png')

On peut alors afficher les images en insérant le fichier comme un lien [[./test1.png]]

test1.png

Et de la même façon pour la deuxième image.

test2.png

9.4 Entrées utilisateur

S'il n'y a pas de 'réaction', on peut écrire la suite des entrées dans un fichier, et utiliser ce fichier en entrée de la ligne de commande.

#include "stdio.h"

int main(int argc, char ** argv){
  (void) argc;
  (void) argv;

  int tab[4];
  char txt[255];

  puts("Entrer 4 entiers");
  for (int i = 0 ; i < 4 ; ++i){
    scanf("%d", &tab[i]);
  }
  puts("\n--------------------     FAIT     --------------------");

  printf("Entrer une chaîne de caractères :");
  scanf("%254s", txt);
  puts("\n--------------------     FAIT     --------------------");    

  for(int i = 0 ; i < 4 ; ++i){
    printf("%s\tn° %d\n", txt, tab[i]);
  }

} 

9.5 Pour expliquer un code

  1. Référencer une portion de code

    Il est parfois intéressant de référencer une portion de code afin d'y faire appel dans le texte. Cela peut se faire en plaçant dans le code une référence sur une ligne de code (ref:label) (où label est remplacé par une étiquette de son choix). Dans le texte, on pourra alors faire un lien sur la ligne de code par \([\)[(label)][Texte à afficher]\(]\)

    def fact(n):
      if n <= 1:
        return 1
      else:
        return n * fact(n-1)
    
    print("fact(5) =", fact(n) ) 
    print("| hello |")
    
    fact(5) = 720
    | hello |
    

    "On pourra noter que le cas de base est ici étendu au cas où l'argument vaut 1, ce qui n'est pas nécessaire, la partie récursive est, elle, conforme à la définition usuelle de la factorielle"

  2. Numéroter les lignes

    L'option -r permet d’afficher dans le texte le numéro de la ligne.

  3. Bloc de code sans langage précisé

    Permet d'obtenir un paragraphe séparé du reste avec une fonte à chasse fixe.

    #+BEGIN_SRC python :tangle results value  :exports both
      def fact(n):
        if n <= 1:                     
          return 1
        else:                          
          return n * fact(n-1)
    
      print("fact(5) =", fact(5) ) 
    #+END_SRC
    

9.6 Export d'un code pour être utilisé ailleurs

9.6.1 Export du code

Pour effectuer cette forme d'export, on utilise C-c C-v t. Le résultat est un nouveau fichier qui ne contient que ce code source.

def hello():
  print("hello World")

On peut compléter le fichier en réalisant des 'tangles' en utilisant le même nom de fichier, mais attention, le 'tangle' ne fait que copier les textes dans le fichier indiqué, il ne vérifie rien !

hello()

Ou écrire dans un autre fichier :

print("ici est ailleurs")

9.6.2 Bash pour exécuter ce code

  • On crée un fichier à l'aide de la méthode précédente
int main(){
  puts("Salut les copains !");
  return 0;
} 
  • Puis on travaille un peu en bash :
gcc -Wall -Wextra -o hello hello.c
./hello

9.7 Appeler une fonction

  1. un exemple en python
    def fact(n):
      if n <= 1:                      
        return 1
      else:                           
        return n * fact(n-1)
    
    def succ(n):
      return n+1 
    
    5040

    Lorsque comme ci-dessus une variable a été définie, il est possible de rappeler le code en modifiant la valeur de la variable. Pour cela on utilise #+call: fct(n=5), où (ATTENTION !) fct est le nom du bloc de code (et pas le nom de la fonction), indiqué par le #+name: fct précédant le code. On peut noter qu'el est possible de modifier les options lors de cet appel si on le désire.

    On peut également appeler une autre fonction :

    6
  2. un exemple en c
      int f(int n){
        return n==0?1:n*f(n-1);
      }
    
      int main(){
    //printf("| ");
    for(int i = 0 ; i< n ; ++i){
        printf(" %d | ", f(i));
    }
        return 0;
      }
    

    et avec un appel avec la valeur 7 :

    1 1 2 6 24 120 720

    Ce qui est bel et bien bon !

9.8 Communiquer entre des blocs de code

9.8.1 Utiliser des fichiers

Un premier code prodit ses résultats dans un fichier, qui sert d'entrée à un autre code. Cela peut être fait sans utiliser de fonctionnalité d'orgmode (les codes utilisent de façon normale des fichiers), ou en utilisant comme variables d'entrées ou de sorties des fichiers (c'est alors très similaire aux redirections < et > du bash).

  1. Exemple en passant par la ligne de commande

    Voici un bloc en c qui produit des données :

    #include "stdio.h"
    
    int main(int argc, char **argv){
      (void) argc;
      (void) argv;
      int i;
    
      for(i = 0 ; i < 100 ; ++i){
        printf("%d\n", i);
      }
    
      printf("%s", "Hello!");
    
      return 0;
    }
    

    Maintenant un bloc en python qui consomme les données :

    import sys
    
    import seaborn as sns
    import matplotlib.pyplot as plt
    
    sys.stdin = open('c_to_py.txt', 'r')
    L = []
    for a in range(10):
        L.append(int(input("")))
    sys.stdin.close()
    
    L = list(map(lambda x: x**2, L) )
    sns.lineplot(x = range(len(L)), y = L)  
    plt.savefig('test3.png')  
    print(L)
    
    sys.stdout = open('py_to_c.txt', 'w')
    for a in L:
      print(a)
    
    sys.stdout.close()
    
    

    None test3.png

    orgmode/py_to_c.txt

9.8.2 Nommer les sorties

On peut nommer avec #+NAME mon_joli_nom un bloc . Ce bloc peut alors être utilisé comme variable d'entrée à un autre bloc.

Un bloc en C qui fabrique des arcs :

#include "stdio.h"
#include "stdlib.h"


int main(int argc, char ** argv){
  (void) argc;
  (void) argv;
  srand(143); 

  int i, k;

  for(i = 0 ; i < 10 ; ++i){
    for (k = 0 ; k < rand()%5+1; ++k){
      printf("%d -> %d\n", i, rand()%10);
    }
  }


  return 0; 
}

orgmode/c_to_gv.txt Pour finalement être représenté sous forme de graphe :

strict digraph {
 $monGraph
}

graph2.png

9.9 Un exercice Codingame

9.9.1 Sujet

On considère une chaîne de caractères b constituée de '0' et de '1'. Déterminer la plus longue chaîne de '1' consécutifs qu'il est possible d'obtenir, en permutant un bit de l'état '0' à l'état '1'.

9.9.2 Code

#include <stdio.h>
#include <string.h>

long max(long u, long v){
  return u<v?v:u;
}

int main(){
  long
    best_lg = 1,
    before_lg = 0,
    after_lg = 0,
    lg;

  char b[1001];

  scanf("%[^\n]", b);
  lg = strlen(b);

  b[lg++] = '0';
  b[lg] = '\0';

  for(int i = 0 ; i < lg ; ++i){
    if(b[i] == '1'){
      ++ after_lg;
    } else{
      best_lg = max(best_lg,after_lg + before_lg +1);
      before_lg = after_lg;
      after_lg = 0;
    }
  }
  printf("%ld\n", best_lg);
  return 0;
}

9.9.3 Enoncé des tests

  1. Test1

    "00"

    1

  2. Test2

    "00010111111001000101011111111010"

    15

    la bonne valeur est 13, pas 15, c'est uniquement pour voir ce qui se passe s'il y a erreur

  3. Test3

    "010001100101101100111010110010111000111010011101100000001110100100000111011100110001011100011011110011010111110101100000110001011010011011000000011000101001011101101110011100000110101100001001111011000000001000110011000001111110000010111001111000100010100001100011111001111011110101000010001101101001000000001010000101010101101011101000000010101110111010100001000010011100010110111111111010001000110010010110100110011101001110001000101001111111111111011111111101110110000001001110010010110100001101010010010101011010010001111001000010100110110100011000110100101111001011111100101110001010100100010010111100101110111011010100110011010001101011000000111110011010010100010010100111000010111000100110010100110111010101111001110111011011000100110100100101010110110001000100111110000111001110100110101100011010001101001101100010110100110110011101000000111001010101100011010111110100000100000011111110000111101001001110001000100101011011000000111100000111110010011000101001001100000110110111010111011110100"

    23

9.9.4 Fonctions pour les tests

gcc -Wall -Wextra $file_in -o $file_out 
import os

f = open("test.in", "w")
for u in test_in:
  f.write(u) 
f.close()

stream = os.popen(exe+" <test.in")
output = stream.read()

if output==test_out:
   print("Test réussi")
else:
   print("Echec du test" )  
   print("obtenu :\t", output)
   print("désiré :\t", test_out)

9.9.5 Exécution des tests

Echec du test
obtenu :	 
désiré :	 1

Echec du test
obtenu :	 
désiré :	 15

Echec du test
obtenu :	 
désiré :	 23

9.10 Test graphe circulaire

  strict digraph {
      a -> b
      b -> c
      c -> d
      d -> a
}

graph1.png

9.11 Couper un code en morceaux

9.11.1 Présentation

Le tag permettant de découper aisément du code est :noweb-ref. Tout se passe comme si des copier/coller étaient réalisés entre les blocs de code précisés (ou dans certains cas des résultats des évaluations des blocs de code). Ce tag peut prendre entre autres comme valeurs :

  • yes : c'est la valeur à utiliser par défaut
  • no : peut servir à annuler un 'yes' défini globalement
  • tangle : l'expansion se fera sur les fichiers générés, mais ni dans les exports, ni dans l'exécution des codes du fichier orgmode
  • no-export : l'expansion ne se fait pas dans les exports (cela peut éviter de répéter des blocs de code, cette valeur est souvent assez agréable)

9.11.2 Utilisation

  1. On définit des blocs de code nommés,
  2. dans le bloc qui exécute les morceaux, on précise la valeur du tag noweb,
  3. dans le bloc d'exécution on insère les sous-blocs par <<nom_sous-bloc>>
  1. exemple 1
    1. Premier morceau

      Header :

      #+name: affiche_hello
      #+begin_src C :results none
      

      Code:

      printf("hello\n");
      
    2. Deuxième morceau

      Header :

      #+name: ajoute_un
      #+begin_src C :results none
      

      Code

      int add1(int x){
        return x+1;
      }  
      
    3. Un premier programme appelant

      Header

      #+name: main1
      #+begin_src C :exports both :noweb yes :results output
      

      Code

      #include <stdio.h>
      
      int main(){
        puts("** Prog 1 **");
        printf("hello\n");
      
        return 0;
      }
      
      ** Prog 1 **
      hello
      
    4. Un deuxième programme appelant

      Header

      #+name: main2
      #+begin_src C :exports both :noweb no-export :results output
      

      Code

      #include <stdio.h>
      
      <<ajoute_un>>
      
      int main(){
        puts("** Prog 2 **");
        <<affiche_hello>>
        printf("le successeur de %d est %d", 42, add1(42));
      
        return 0;
      }
      
      ** Prog 2 **
      hello
      le successeur de 42 est 43
      
  2. Voir le résultat de la substitution

    Afin de voir le résultat d'une substitution : C-c C-v v

9.12 Les tags globaux / semi-globaux

Il est souvent intéressant de définir des tags qui seront utilisés par défaut. La valeur de ces tags peut être redéfinie localement lorsque leurs valeurs ne correspondent pas au cas que l'on traite. On peut compléter un tag à condition de ne pas oublier le '+' dans la syntaxe, sinon le tag est redéfini au lieu d'être complété.

9.12.1 Tags globaux

On peut définir des tags valides sur la totalité du code par :

#+PROPERTY: header-args:C  :exports both 
#+PROPERTY: header-args:C+ :noweb yes

9.12.2 Tag semi-glogaux

Ces tags opèrent sur une sous arborescence. Ils sont définis dans un 'tiroir'. On peut compléter un tag à condition de ne pas oublier le '+' dans la syntaxe, sinon le tag est redéfini au lieu d'être complété.

**Attention, pour être valides, il est obligatoire que ce tiroir soit défini juste après le titre du sous arbre auquel il s'applique (ne pas même le séparer par un saut de ligne).**

:properties:
:header-args:C: :exports both
:header-args:C+: :noweb no-export
:end:

10 Navigateur internet

Un projet a vu le jour ces dernières années qui permet d'obtenir enfin un navigateur internet, et des fonctionnalités liées à ce navigateur à l'intérieur d'emacs. Ce projet est eaf = emacs application framework. Il nécessite d'installer un certain nombre de bibliothèques, et… de bien suivre les indications pour l'installer. Une fois en place, il donne accès à différentes nouvelles fonctionnalités dans emacs [extrait de la doc] :

  • Browser: Full-featured browser
  • PDF Viewer: The fastest PDF reader
  • Terminal: Full-featured terminal
  • Video Player: Video player base on Qt
  • Markdown Previewer: Markdown file previewer in Emacs
  • Org Previewer: Org file previewer in Emacs
  • Music Player: Music player, support playlist and an audio visualization
  • RSS Reader: RSS reader, rendering html content in expected
  • File Manager: File manager, support file real-time preview
  • Mindmap: Mindmap with full-featured keyboard operation
  • Jupyter: Jupyter in Emacs
  • Image Viewer: Picture viewer, supporting real-time zoom rotation
  • Camera: Use camera in Emacs
  • System Monitor: System monitor base on Vue.js
  • Netease Cloud Music: EAF frontend for NetEase cloud music
  • File Browser: Browse file in mobile phone
  • File Sender: Share file between Emacs and mobile phone
  • Airshare: Share text between Emacs and mobile phone
  • Demo: EAF Application demo base on Qt
  • Vue Demo: EAF Application demo base on Vue.js

11 TODO Org : remplacer google agenda ?

Désolé, mais ce ne sera pas présenté ici, mais cela marche très bien. On peut d'ailleurs faire un lien afin de fusionner les agendas à la mode (bien agréables pour les téléphones portables) et orgmode.

12 TODO Org : remplacer Jira ?

La gestion de projets 'agiles' avec des outils de planification, de gestion de tickets, etc… avec un logiciel type Jira ne peut qu'être esquissée avec orgmode, mais pour ce qui est d'une utilisation personnelle (et non pour des équipes), cela peut tout à fait faire l'affaire. Je ne pense pas que cela soit une des premières choses à faire avec orgmode, mais repensez-y après en avoir utilisé un logiciel de ce type, cela devrait vous donner des idées pour de nouvelles utilisations d'orgmode.

Notes de bas de page:

1

Certains prétendent que Linux n'est en réalité que le fichier de chargement d'Emacs (il existe d'ailleurs un greffon pour emacs qui le transforme en window manager (exwm) mais je ne l’utilise pas et ne vous le conseille pas réellement… enfin bon, si vous sous y mettez, je vous serai reconnaissant de me faire un retour d’expérience).

Auteur: Yves-Jean DANIEL Yves-Jean DANIEL

Created: 2022-05-23 lun. 14:18

Validate