Articles du blog - Page 1
Récupérer les images d’une galerie en python
Quand je veux récupérer plusieurs pages, je le fais souvent avec
wget
. L’utilisation des options --load-cookies
, --save-cookies
et --keep-session-cookies
avec --post-data
étant plus que
pratique. Pour parser, ensuite, c’est souvent pénible, même si awk
est là pour aider.
man wget
donne :
# Log in to the server. This can be done only once. wget --save-cookies cookies.txt \ --post-data 'user=foo&password=bar' \ http://server.com/auth.php # Now grab the page or pages we care about. wget --load-cookies cookies.txt \ -p http://server.com/interesting/article.php
Pour parser, j’aime bien python ; je trouve ça plus lisible. Par contre, ce que j’utilisais jusqu’à présent pour me logguer sur une page était moins glop :
import urllib, urllib2, cookielib username = 'foo' password = 'bar' cj = cookielib.CookieJar() handle = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj)) login_data = urllib.urlencode({'username' : username, 'pwd' : password}) handle.open('http://www.example.com/login.php', login_data) res = handle.open('http://www.example.com/my_account.php') print res.read()
Mais ça, c’était avant. Depuis, j’ai découvert Requests. Pour faire un
POST
, c’est aussi simple que :
import requests url= 'http://www.example.com/login.php' login_data = {username = 'myuser', password = 'mypassword'} req = requests.post(url, login_data) page = req.content
Si on a besoin de gérer les cookies, on peut passer par une Session
:
import requests url= 'http://www.example.com' login_data = {username = 'myuser', password = 'mypassword'} s = requests.Session() req = s.post(url + '/login.php', login_data) req = s.get(url + '/my_account.php')
C’est quand même plus lisible, non ?
En fait, récemment, je voulais parcourir les images de la galerie d’un site. Mais cette galerie contenait 10 images seulement par page, pour 40 pages. J’ai donc fait un script pour mettre toutes les images sur une seule page.
Les images sont encapsulées par une balise a class="foo"
et donc
j’utilise BeautifulSoup
pour toutes les lister
(soup.findAll("a","foo")
).
Comme j’ai « besoin » de consulter les images plusieurs fois, j’ai
préféré enregistrer les images en local plutôt que de laisser un lien
sur le site. Pour ça j’ai utilisé stream=True
de la méthode .get
(cf ce lien sur SO).
J’ai pas fait très propre puisque j’affiche la page sur stdout
que
je pipe avec tee
pour mettre dans un fichier. Mais au moins, je vois
si ça marche :þ
# -*- coding: utf-8 -*- from BeautifulSoup import BeautifulSoup from requests import session login_data = { 'login': 'fredtantini', 'password': 'toto1234', 'action': 1 } urlToVisit = 'http://www.example.com' #on ouvre une session with session() as s: #on se connecte req = s.post(urlToVisit + '/login.php', data=login_data) print "<html><body>" #comme je sais qu’il y a 40 pages for nPage in xrange(1,41): #on récupère la page request = s.get(urlToVisit + '/some_page.php?p='+str(nPage)) #que l’on passe à BS soup = BeautifulSoup(request.text) print "<h1> Page - ",nPage,"</h1>" #Pour tous les liens for i in soup.findAll("a","foo"): #on récupère l’image r = s.get(urlToVisit + '/' + i.img['src'], stream=True) #on la télécharge par parties (cf lien SO plus haut) if r.status_code == 200: with open(i.img['alt'] + ".jpg", 'wb') as f: for chunk in r.iter_content(): f.write(chunk) print str(i).replace('./images/', './') print "</body></html>"
Quelques notes SoapUI
Voici un premier article sur SoapUI. Un second arrivera prochainement :]
Les informations sont un peu brutes, cela me sert surtout de notes. Du
coup, c’est directement technique et suppose que vous connaissiez déjà
SoapUI. D’abord un « rappel » sur les property expansions
puis
comment on peut passer des paramètres entre les différents pas du cas
de test et comment faire des assertions variables.
Property Expansion
Voir property expansion (soapui.org).
À l’intérieur d’une requête/assertion/… on peut mettre des choses
comme ${[scope]propertyName[#xpath-expression]}
. Avec scope
parmi :
#Project#
;#TestSuite#
;#TestCase#
;#MockService#
;#Global#
;#System#
;#Env#
;[TestStep name]#
.
Par exemple ${Search
Request#Response#//ns1:Item[1]/n1:Author[1]/text()}
prend la réponse
(propertyName
= Response
) du step Search Request
(scope
=
Search Request#
) et prend le texte du nœud Item/Author
(xpath-expression
= #//ns1:Item[1]/n1:Author[1]/text()
).
On peut également utiliser une expression groovy avec ${= expr
groovy)
à l’intérieur d’une requête :
${=(int)(Math.random()*1000)}
insère un nombre aléatoire entre 0 et 999.${=request.operation.interface.project.name}
insère le nom du projet (on part de la requète et on remonte l’arbre soapUI ModelItem.
Passer des paramètres entre test steps
On va voir comment récupérer des valeurs dans un test step. Tout d’abord, créer des propriétés dans le projet (ou le testSuite ou le testCase).
- Cliquer sur le projet.
- Cliquer sur
Custom Properties
. - Ajouter des propriétés. (Pour cet exemple :
login
etdatejma
.)
On va les changer dès l’initialisation, donc pas besoin de mettre des valeurs.
Dans le test Case
On se place maintenant au niveau du cas de test et on va initialiser nos deux « propriétés ».
Initialisations
Voir scripting and the script library (soapui.org).
On peut initialiser grâce à un Groovy Script
que l’on renommera init
par
exemple, ou alors dans le test Case
, dans Setup Script
.
Dans les deux cas, on ajoute :
def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context ) //on définit nos variables def login = "user" + System.currentTimeMillis().toString()[-5..-1] //user12345 def datejma = new Date().format("dd/MM/yyyy") //on change les propriétés du projet testRunner.testCase.testSuite.project.setPropertyValue("login", login) testRunner.testCase.testSuite.project.setPropertyValue("datejma" ,datejma) //on récupère la requête du step authentification def holder = groovyUtils.getXmlHolder("authentification#Request") holder.namespaces["ns"] = "http://schemas.xmlsoap.org/soap/envelope/" //On change le noeud qui va bien (<in0...>user12345</in0>) holder.setNodeValue("//ns:Body/*/in0", login) //On met à jour les changements dans l’enveloppe holder.updateProperty()
Une ligne comme testRunner.testCase.testSuite.project.setPropertyValue("maPropriete",
maValeur)
permet d’instancier maPropriete
à la valeur maValeur
dans les Custom Properties
du projet. (get and set properties (soapui.org).)
- Si on enlève
.project
on change la propriété dans la test suite. - Si on enlève
.testSuite.project
on change dans le test case.
Ici, on définit donc deux variables et on instancie les propriétés du projet à ces valeurs.
On met ensuite l’enveloppe de la requête à jour. Dans cette exemple,
on pourrait bien évidemment mettre directement dans le nœud <in0...>${#Project#login}</in0>
Passage de valeurs entre Steps
On peut également récupérer la valeur d’une balise d’une réponse pour s’en servir dans la requête suivante.
Pour cela, on peut ajouter un step property transfer
.
On choisit les propriétés de la source (Request
ou Response
d’un
step), de la cible, puis on choisit le nœud à extraire/renseigner. Par
exemple :
declare namespace ns = "http://schemas.xmlsoap.org/soap/envelope/"; //soap:Body/*/retour/idSession
dans la source et
declare namespace ns = "http://schemas.xmlsoap.org/soap/envelope/"; //soap:Header/*/identification/idSession
dans la cible.
Assertions
On va voir ici comment vérifier que la balise d’une réponse contient bien ce que l’on veut. Parce que « Contains » peut être assez limité (même avec des regexp), on va voir comment utiliser XPath Match, puis un script.
XPath Match
On choisit le nœud a tester :
declare namespace ns = "http://schemas.xmlsoap.org/soap/envelope/"; //ns:Body/*/maBalise
On dit ce que l’on attend :
${#Project#login},1234 * auie,${#Project#datejma}
Le *
, lorsque Allow Wildcards
est coché, permet de matcher
n’importe quelle valeur. (Voir xpath and xquery assertions
(soapui.org). J’ai eu des soucis lorsqu’il y en a plusieurs, ou comme
ici, lorsqu’on l’utilise avec les property expansions.)
script Assertion
Voir script assertions (soapui.org).
On peut également utiliser un script groovy si l’on veut faire des choses plus poussées. Bon, là l’exemple est le plus simple possible :
groovyUtils = new com.eviware.soapui.support.GroovyUtils(context) //la requete holder = groovyUtils.getXmlHolder( "authentification#Request" ) holder.namespaces["ns"] = "http://schemas.xmlsoap.org/soap/envelope/" reqLogin = holder.getNodeValue("//ns:Body/*/in0") //la reponse holder2 = groovyUtils.getXmlHolder( "authentification#Request" ) holder2.namespaces["ns"] = "http://schemas.xmlsoap.org/soap/envelope/" repLogin = holder2.getNodeValue("//ns:Body/*/libelleCodeRetour") //on teste que la reponse est bien celle attendue assert repLogin.equals(reqLogin)
Bien pratique si l’on veut formatter la chaîne (mettre en capitales par exemple, supprimer les traits d’union…).
Liens (potentiellement) utiles
Différence entre eval-after-load
et add-hook
J’expliquais dans le billet sur le démarrage d’Emacs que
le code de eval-after-load sera exécuté seulement une fois […]
Les nomdumode-mode-hooks, eux, sont exécutés pour chaque buffer dans lequel le mode sera activé.
Pour illustrer mes propos, voici un code à mettre dans un nouveau buffer (C-x b auie) :
(setq auie 0) (setq nrst 0) (eval-after-load "python" ;puisque dans python.el '(progn (setq auie (1+ auie)) )) (add-hook 'python-mode-hook (lambda () (setq nrst (1+ nrst)) )) (progn (python-mode) (message (concat "auie vaut :" (number-to-string auie) ", nrst : " (number-to-string nrst))))
Passez en mode elisp (M-x emacs-lisp-mode), puis évaluez le buffer
(M-x eval-buffer). Un petit message devrait s’afficher. Allez à la
fin du buffer (M->) et évaluez la dernière sexp (C-x C-e). Évaluez
plusieurs fois ; constatez que auie
n’augmente pas, nrst
si.
Autrement dit, si l’on veut exécuter du code lorsque l’on passe dans
le mode foo
, et que l’on ne veut pas charger le fichier foo.el
ni
faire un (require 'foo)
dans son fichier init.el
, on a deux
possibilités :
- Utiliser
eval-after-load
pour exécuter du code une fois. - Utiliser
add-hook
pour exécuter du code plusieurs fois.
En fait, eval-after-load
va exécuter le code à chaque fois que la
bibliothèque est chargée. Mais généralement, on fait un (autoload
'foo-mode "foo" "docstring")
; au premier appel de foo-mode
(avec
un M-x ou avec un add-to-list 'auto-mode-alist
), foo.el
est
chargé et le code du eval-after-load
est exécuté. Aux prochains
appels de foo-mode
, foo.el
est déjà chargé, le code n’est plus
exécuté.
eval-after-load
est donc approprié si l’on veut changer des valeurs
par défaut :
(eval-after-load "ace-jump-mode" '(ace-jump-mode-enable-mark-sync)) ;par défaut, c’est à disable (eval-after-load "foo-mode" '(my-init-foo-mode)) ; on charge des choses en plus (eval-after-load "org" '(require 'ox-md nil t)) ;l’export markdown n’est pas chargé automatiquement (eval-after-load 'foo-mode '(define-key foo-mode-map (kbd "C-à") 'my-useful-fonction)) ; un raccourci utilisé seulement pour ce mode
Le add-hook
lui est utilisé à chaque fois que foo-mode
est lancé
(et non pas à chaque fois que foo.el
est chargé). C’est ce choix que
l’on fera si l’on veut activer un minor mode pour un major mode ou si on
veut changer des valeurs de variables changées par le major mode.
; à chaque fois que l’on passe en elisp mode, on met les parenthèses en couleur (add-hook 'emacs-lisp-mode 'rainbow-delimiters-mode) ;avant de sauver, on lance un nettoyage (add-hook 'before-save-hook 'whitespace-cleanup) ;le mode foo redéfinit à chaque fois C-> et je ne veux pas (add-hook 'foo-mode-hook '(lambda () (define-key foo-mode-map "\C->" 'foobar))) ;on met c-basic-offset à 4 (add-hook 'c-mode-common-hook '(lambda () (setq c-basic-offset 4))) ;si on veut différentes valeurs selon que l’on soit en foo ou en bar (add-hook foo-mode-hook '(lambda () (setq spam 42)) nil t) (add-hook bar-mode-hook '(lambda () (setq spam 3.14)) nil t)
En espérant avoir été clair.
Rubrique-en-Vrac
Du divers, du varié, mais que de l’Emacs aujourd’hui (ce qui laisse présager autre chose dans un futur… lointain). Voire, que des choses qui sont à installer.
Je n’ai pas forcément tout testé et je ne testerai pas tout. Mais je suis sûr que ça peut servir à d’autres.
ace-jump-mode
Pour se déplacer n’importe où dans la fenêtre rapidement.
Après avoir fait C-c SPc, on rentre la lettre du début d’un mot, et
tous les mots dont la première lettre correspond ont la première
lettre qui devient a
, b
, c
… Il ne reste plus qu’à choisir la
lettre qui correspond au mot sur lequel on veut aller.
Il est également possible de choisir une lettre dans un mot (C-u C-c SPC ou C-c C-c lors d’une requête) ou une ligne (C-u C-u C-c SPC). Avec la version 2, on peut naviguer entre les buffers (si on a splitté avec C-x 2 par exemple).
source de l’image, sources (github.com), démonstration (emacsrocks.com)
auto-revert-tail-mode
Quand on surveille des logs avec tail -f
on voit les ajouts en fin
de fichier. Quand en fichier est modifié par un autre programme, dans
Emacs on peut faire un M-x revert-buffer. Et sinon, on peut utiliser
le mode approprié : auto-revert-tail-mode
(dans autorevert.el
, qui
est inclus dans Emacs).
highlight-changes-mode
Dans le même genre et dans hilit-chg.el
(inclus par défaut aussi),
ce mode rend visible les changements du buffer. On peut également
mettre en avant les changements du buffer par rapport au fichier,
comparer des buffers… Les couleurs par défaut sont un peu trop…
colorés et TrackChanges (emacswiki) présente des astuces pour changer
ça et d’autres infos pour connaître les changement d’un fichier ou
d’un buffer.
company-mode
Pour COMPlete ANYthing : une popup qui affiche les complétions
possibles. Comme auto-complete
, mais apparemment, en moins buggué.
easy-kill
« Kill & Mark Things Easily in Emacs »
Pour sélectionner facilement mot, sexp, list, defun… étendre la sélection, la réduire, etc.
Contrairement à expand-region
, il ne me semble pas que l’on puisse
étendre des deux côtés.
expand-region
Pour augmenter la région par unité sémantique. Par exemple
(setq alphabet-start "abc def")
Avec le curseur sur le c
, ça commence par marquer le mot abc
en
entier, puis on augmente la région à abc def
, puis aux guillemets
"abc def"
, ensuite au contenu des parenthèses setq alphabet-start
"abc def"
et enfin à toute la sexp.
Plus lourd que easy-kill
, mais peut-être plus pratique aussi…
fancy-narrow
Comme comme narrow-to-region
(C-x n n), mais au lieu de supprimer
le texte autour de la région, ce dernier est grisé.
god-mode
Pour ne plus avoir à appuyer sur la touche Ctrl.
Après un appui sur ESC, au lieu de taper C-a C-k C-n C-y, on a juste besoin d’appuyer sur akny. Au lieu de M-f M-f M-f on tape gf...
Une sorte de séparation commandes/insertions à la vi. À rapprocher d’Evil (gitorious).
guide-key
Ce mode sert à afficher les suites possibles d'un raccourci dans une fenêtre. Par exemple, si on ne se souvient jamais des différentes suites de C-x r qui mèle à la fois rectangle et registre, on aura tendance à faire C-x r C-h. Ce qui affichera un buffer d’aide et perdra la séquence en cours.
Avec ce mode, paramétré correctement, on peut visualiser facilement les suites qui ne concernent que les rectangles :
impatient-mode
Pour voir le changement dans le navigateur dès qu'on tape dans le buffer.
keychord
Pour lancer une commande quand on appuie sur 2 touches en même temps.
Comme s’il n’y avait pas assez de raccourcis…
sources (emacswiki), What are your key-chord abbreviations? (reddit)
make-it-so
Pour faire de la conversion en masse via un Makefile.
Et ça dans Emacs, sisisi. En fait, on met la commande de conversion
dans un Makefile (avec d’autres choses), et une fois dans un dossier
(en dired-mode
donc), on appelle make-it-so
qui propose suivant
les extensions disponibles les conversions possibles.
manage-minor-mode
Un mode pour gérer les minor modes facilement.
Ça les liste dans un buffer, et on peut activer/désactiver simplement.
rainbow-delimiters
Pour des parenthèses/crochets/… en couleur pour savoir où on en est.
source de l’image, sources (github), Plus d'info (emacswiki)
Existe aussi pour mettre en couleur tout le bloc, et pas seulement la parenthèse/crochet : rainbow-blocks (github)
visual-regexp
Comme replace-regexp
, mais avec des couleurs pour chaque partie de la regexp.
On voit aussi le remplacement lorsque l’on utilise des \1
web-mode
Major mode pour html + block php/jsp/template
Indentation, coloration, commentaires qui dépend du contexte (html/code/js/css?), et plein d’autres choses qui permettent de travailler sur un fichier html qui contient du js, du css, du php, de l’asp, du go, etc.
which-function-mode
Pour afficher le nom de la fonction dans la mode-line
(dans
which-func.el
).
On peut aussi faire afficher le nom en première ligne (cf which-function-mode (emacsredux)).
Raccourcis utilisés
C-c ^ a
Pour trier alphabétiquement mes entrées
C-c C-x C-f
Pour marquer une sélection avec =
, ‰
, etc.
Sources des images
J’ai enregistré chaque image plutôt que de pointer sur le site.
Toutes les images proviennent du premier lien suivant l’image.
Le démarrage d’Emacs
Introduction
Il y a quelques temps de cela (je viens de me rendre compte que cela
fait plus de 10 ans déjà…), je commençais à utiliser Emacs. Et, comme
beaucoup je suppose, pour configurer, je copiais/collais des bouts de
code dans mon .emacs
sans chercher à comprendre ce que ça faisait
(comment ça c’est encore le cas ‽). Typiquement, j’avais plein de :
(autoload 'php-mode "php-mode" "Major mode for editing php code." t) (add-to-list 'auto-mode-alist '("\\.php$" . php-mode))
plutôt obscurs.
Et au fil du temps, les lignes s’accumulaient, et Emacs n’était plus aussi rapide à charger.
Je me suis alors intéressé à comment le rendre plus rapide au démarrage. Bien que je me sois rendu compte que la meilleure solution pour moi serait d’utiliser emacsclient1, j’ai d’abord fait du nettoyage, en utilisant le plus possible customize et en regroupant ça dans un seul fichier avec :
(setq custom-file "~/.emacs.d/config/custom.el") (load custom-file)
Puis j’ai supprimé tout ce dont je ne me servais en fait pas, et je me suis penché sur ce qu’il se passe au démarrage d’Emacs, pour savoir si je ne lui faisais pas faire des choses inutiles. Et, avec les différentes versions d’Emacs certainement, j’ai bien vu que la plupart de ces lignes étaient (devenues ?) inutiles.
tl;dr
Que fait autoload
? Qu’y a-t-il dans auto-mode-alist
? Le bout de
code précédent pour avoir le mode python est-il nécessaire ?
suffisant ? Peut-on faire autrement ? C’est à ça que je vais
m’intéresser par la suite. Pour cela, je me suis penché dans le code
et le manuel d’Emacs et je vous partage ce que j’en ai retenu et
laisse des informations pas forcément pertinentes, mais fortement en
relation et toujours instructives.
Pour ceux qui ne veulent pas tout lire : ça se passe là.
Table of Contents
- Récupérer les images d’une galerie en python
- Quelques notes SoapUI
- Différence entre
eval-after-load
etadd-hook
- Rubrique-en-Vrac
- Le démarrage d’Emacs
- Introduction
- Comprendre ce qui est chargé et lancé au démarrage.
- Savoir comment charger une fonction/un fichier.
- How Programs Do Loading: The load function and others.
- Load Suffixes: Details about the suffixes that load tries.
- Library Search: Finding a library to load.
- Loading Non-ASCII: Non-ASCII characters in Emacs Lisp files.
- Autoload: Setting up a function to autoload.
- Repeated Loading: Precautions about loading a file twice.
- Named Features: Loading a library if it isn't already loaded.
- Where Defined: Finding which file defined a certain symbol.
- Unloading: How to "unload" a library that was loaded.
- Hooks for Loading: Providing code to be run when particular libraries are loaded.
- En bref
- Comment est choisi le mode d’un fichier
- Hooks
- Conclusion
- Edit dans dired/occured = awesome
- Un peu de typographie et marquer les raccourcis clavier dans org-mode
- Une espace une tabulation
- Relancer une précédente commande en ksh
- Des raccourcis en vrac
Comprendre ce qui est chargé et lancé au démarrage.
Cette partie ne se focalise pas sur tout ce qui est fait au
démarrage, mais mets l’accent sur qu’est-ce que charge Emacs, et où il
va chercher ce qu’il charge, pour mieux comprendre comment faire son
.emacs
, et qu’il soit plus léger/rapide (charger un fichier =
ouvrir + évaluer tout ce qu’il y a dedans).
Un bon résumé des opérations effectuées par Emacs est disponible, comme toujours, dans le manuel : Startup-Summary (manuel elisp).
La variable top-level
contient la fonction (en fait la form
, objet
Lisp qui est sensé être évalué ~ expression, mais je laisserai form
par la suite) qui sera lancée au démarrage. Par défaut, c’est
normal-top-level
.
normal-top-level
La fonction normal-top-level
est donc appelée au lancement
d’Emacs. On peut la voir dans le fichier startup.el
2 (pour
trouver le fichier, taper dans Emacs M-x find-library startup.
Ou, via l’aide avec C-h f normal-top-level (juste q pour fermer
les fenêtres d’aide), si emacs2x-el
est installé, la première
ligne devrait être normal-top-level is a compiled Lisp function in
`startup.el'.
avec startup.el
qui est un lien).
Elle :
- fait diverses configurations tout au long de son appel (qui ne nous concerne pas pour le sujet présent) ;
- cherche des
subdirs.el/leim-list.el
dans chaque dossier deload-path
et les charge3 ; - lance la fonction
command-line
; - lance des hooks comme
emacs-startup-hook
etwindow-setup
.Bref, elle initialise, remplit un peu plus la variable
load-path
, et surtout délègue àcommand-line
.
command-line
Aussi située dans startup.el
, cette fonction :
- fait aussi des configurations tout du long ;
- initialise
before-init-time
; - met en chemin absolu les noms de fichiers dans
load-history
(C-h v load-history pour prendre peur) ; - definit le fichier init de quel utilisateur il faut utiliser ;
- parse quelques options de la ligne de commande (
-d
,-D
,-q
,-Q
,-nbc
, etc.) ; - lance
before-init-hook
; - charge
site-run-file
; - cherche le fichier init (cf plus tard) s’il existe et le lit
(puis
default.el
) ; - charge le fichier
abbrev
, s’il existe et qu’Emacs n’est pas en-batch
; - si un dossier de package existe, initialise le système de package
(
package-initialize
) ; - initialise
after-init-time
; - lance
after-init-hook
; - lance
command-line-1
(avec le reste des arguments) ; - appelle
kill-emacs
si option-batch
; - lance le serveur, si Emacs est lancé en démon ;
- lance
emacs-session-restore
.
C’est donc là que sont chargés les fichiers de configuration : site
puis init
et default
. Il faut voir également les hooks
before-init-hook
et after-init-hook
(qui sont définis à nil
par
défaut, mais dont la valeur peut changer selon les systèmes Init-File
(manuel elisp))
La fonction command-line-1
boucle pour chaque option, exécute
l’option (potentiellement -L
pour ajouter des dossiers à
load-path
) et se positionne sur le bon buffer, ou affiche le
startup screen
.
Avant d’ajouter des choses dans votre .emacs
, il faut donc vérifier
que ce n’est pas déjà ajouté dans site-run-file
.
Le fichier init
Je traduis ici très grossièrement les parties intéressantes du manuel (Init-File (manuel emacs), manuel que je vous encourage à lire).
Quand Emacs démarre, il essaie de charger un fichier d’initialisation
qui dit comment l’utilisateur souhaite que démarre Emacs (suivant
l’utilisateur, voir Find-Init (manuel emacs)). Emacs cherche le
fichier init parmi ~/.emacs
, ~/.emacs.el
, ou ~/.emacs.d/init.el
.
Il peut également y avoir un fichier init par défaut, qui est la
bibliothèque default.el
, trouvé dans le load-path
. Si elle existe,
elle est chargée à chaque démarrage d’Emacs (sauf si -q
), mais le
fichier init est chargé en premier. S’il met inhibit-default-init
à
non-nil, default
n’est pas chargé.
Il peut y a voir aussi un fichier de démarrage de « site »,
site-start.el
. Il est chargé avant le fichier init, sauf si
--no-site-file
.
Les fichiers default.el
et site-start.el
peuvent être dans
n’importe quel dossier de la variable load-path
(souvent dans un
dossier site-lisp
comme : /usr/local/share/emacs/site-lisp
).
Pour voir le load-path
de votre Emacs en cours : C-h v load-path.
Pour connaître votre fichier init, et donc savoir quel fichier
~/.emacs(.d/init)?.elc?
a été chargé, C-h v user-init-file.
En bref
Au démarrage, il se passe tout un tas de choses, dont le chargement de
plein de fichiers2. Je vais résumé ici les fichiers chargés (et
les fonctions lancées) qui peuvent avoir un impact sur load-path
, et
sur lesquels l’utilisateur peut avoir une influence.
Le load-path
initial contient quelque chose comme :
/.../emacs24/share/emacs/24.3.50/site-lisp /.../emacs24/share/emacs/site-lisp /.../emacs24/share/emacs/24.3.50/lisp
avant même qu’Emacs ne soit lancé.
Puis sont ajoutés les sous-dossiers de ces dossiers (qui sont dans les
subdirs.el
respectifs) récursivement.
Ensuite, Emacs :
- lance
before-init-hook
; - charge le fichier
site-run-file
(si présent et si pas-no-site-file
) qui est commun à tous les utilisateurs et que seul l’admin du site devrait toucher (normalementsite-start.el
) ; - charge le fichier init de l’utilisateur (si pas
-q
), qui peut être~/.emacs
,~/.emacs.el
, ou~/.emacs.d/init.el
; - charge le fichier
default
(normalementdefault.el
) sauf si-q
ou siinhibit-default-init
n’est pas nil ; - lance
after-init-hook
; - ajoute les dossiers passé en argument à l’option
-L
ou-directory
.
Concernant le chargement des fichiers : par défaut (variable
auto-compression-mode
), il cherche la version compressée (.gz
,
jka-compr-load-suffixes
), et si ce n’est pas précisé autrement lors
de l’appel de load
, il cherche avec les extensions .el
, .elc
et
sans extension.
Savoir comment charger une fonction/un fichier.
On va voir ici ce que fait la fonction autoload
et si c’est bien
elle qu’il faut appeler.
Rien de mieux qu’une traduction approximative du manuel et de l’aide pour connaître nos options. Si vous lisez l’anglais, allez donc plutôt voir Loading (manuel elisp), puis allez au résumé.
How Programs Do Loading: The load function and others.
How-Programs-Do-Loading (manuel elisp)
- Function:
load filename &optional missing-ok nomessage nosuffix must-suffix
:Ouvre un fichier lisp, évalue, ferme le fichier.
Cherche d’abord
filename.elc
. Si existe, est chargé. Sinon, cherchefilename.el
. Si existe, est chargé. Sinon, cherchefilename
et charge si existe. (Attention àfoo.el.el
:(load "foo.el")
marche…)Si
auto-compression-mode
est activé (cas par défaut) cherche la version compressée si le fichier n’est pas trouvé, puis passe aux suivants. Décompresse et charge si existe (ajoute chacun des suffixes dansjka-compr-load-suffixes
).Si
nosuffix non-nil
, n’essaie pas d’ajouter.el/.elc
Si
must-suffix non-nil
,load
insiste sur le fait que le nom du fichier doit finir par.el/.elc
.Si
filename
est un nom de fichier relatif (foo ou baz/foo.bar),load
cherche le fichier par la variableload-path
. Il charge le premier fichier possible. Sinil
dansload-path
, essaie le dossier courant. Les trois premiers fichiers dans le premier dossier deload-path
sont tentés, puis les trois du second dossier, etc.Peu importe où Emacs trouve le fichier (nom/dossier) la variable
load-file-name
sera valorisée à ce nom de fichier.Des messages comme
‘Loading foo...’
et‘Loading foo...done’
apparaissent, sauf sinomessage
estnon-nil
.Si
load
ne trouve pas le fichier, normalement, il signale l’erreurfile-error
. Mais simissing-ok non-nil
, alorsload
retourne seulementnil
.load
retournet
si le fichier est chargé avec succès.- Donc
load nomfichier [retourneNilSiAbsent?SinonErreur nonVerbeux? tenteDAjouter.el/.elc? doitFinirPar.el/.elc?]
Du coup, on utilisera le plus souvent
(load "chose")
ou(load "chose.el" t t t)
(avec des variantes sur missing-ok et nomessage).C-h f load : Charger un fichier enregistre ses définitions, ses appels
provide
etrequire
dansload-history
. La variableload-in-progress
est non-nil pendant le chargement,load-file-name
contientle nom du fichier.
- Donc
- Command:
load-file filename
:Charge le fichier
filename
. Sifilemane
est un nom relatif, le dossier courant est présumé. N’utilise pasload-path
, n’utilise pas de suffixes, mais cherche une version compressée.- En très gros, fait
(load (expand-file-name file) nil nil t))
.
- En très gros, fait
- Command:
load-library library
:Cette commande charge la bibliothèque
library
. Commeload
, sauf que lit son argument de façon interactive.- En gros, fait
(load library)
.
- En gros, fait
Load Suffixes: Details about the suffixes that load tries.
Quels suffixes sont tentés (.el
, etc.): voir point précédent.
Library Search: Finding a library to load.
Quand Emacs cherche une bibliothèque, il cherche dans load-path
qui contient des chaînes de caractères correspondant à des dossiers
ou nil
pour le dossier courant.
À chaque démarrage, il initialise load-path
par la variable
d’environnement EMACSLOADPATH
. Si elle n’est pas défini, Emacs
initialise load-path
avec
/usr/local/share/emacs/version/site-lisp
et
/usr/local/share/emacs/site-lisp
et ajoute à load-path
les
sous-dossiers récursivement (sauf si ne commence pas par
chiffre/lettre, vaut CVS
ou RCS
, contient un fichier
.nosearch
). Puis, comme vu précédemment, ajoute ceux indiqués par
-L
, et ceux du fichier init de l’utilisateur.
- Command:
locate-library library &optional nosuffix path interactive-call
:Trouve le vrai nom de la bibliothèque
library
. Cherche comme le faitload
, l’argumentnosuffix
ayant le même sens : ne pas ajouter.elc
ou.el
au nom.Si
path
est non-nil, cette liste de dossier est utilisée au lieu deload-path
.Si la commande est appelé depuis un programme, retourne le nom en tant que
string
. Si appelé avec M-x l’argumentinteractive-call
estt
, et le résultat est affichée dans la zone d’affichage des messages (echo area). - Command:
list-load-path-shadows &optional stringp
:Cette commande montre une liste de fichiers Emacs lisp « occultés » (shadowed). Un fichier occulté est un fichier qui ne sera normalement pas chargé alors qu’il est dans un dossier dans
load-path
, mais parce qu’un autre fichier au nom similaire se situe dans un dossier deload-path
.Par exemple, si
load-path
vaut("/opt/emacs/site-lisp" "/usr/share/emacs/23.3/lisp")
et que dans les deux dossiers un fichierfoo.el
existe, alors(require 'foo)
ne chargera jamais le fichier du second dossier. Une telle situation peut indiquer un problème dans la façon dont Emacs a été installé.Quand appelée depuis Lisp, cette fonction affiche un message contenant la liste des fichiers occultés, plutôt que de les afficher dans un buffer. Si l’argument
stringp
est non-nil, elle retourne les fichiers occultés dans unstring
.
Loading Non-ASCII: Non-ASCII characters in Emacs Lisp files.
Pas pertinent pour le sujet.
Autoload: Setting up a function to autoload.
autoload
permet d’enregistrer l’existence d’une fonction ou macro,
et repousse le chargement du fichier qui la définit. Le premier
appel à la fonction charge automatiquement la bonne bibliothèque,
pour installer la vraie définition (et d’autres choses associées),
puis exécute la définition comme si cela avait déjà été chargé.
L’autoloading peut également être déclanché en regardant la doc
d’une fonction (C-h f).
Il y a deux façons de faire une fonction « autoloaded » : en appelant
autoload
, et en écrivant un commentaire « magique » avant la vraie
définition. autoload
est la primitive bas niveau pour
l’autochargement ; n’importe quel programme Lisp peut appeler
autoload
à n’importe quel moment. Les commentaires magiques sont
le moyen le plus pratique de faire « autoloader » une fonction, pour
les paquets installés avec Emacs. Ces commentaires ne font rien en
eux-même, mais ils servent de guide pour la commande
update-file-autoloads
, qui construit les appels à autoload
et
fait en sorte de les exécuter quand Emacs est construit.
- Function:
autoload function filename &optional docstring interactive type
Cette fonction définit la fonction (ou macro)
function
pour pouvoir charger automatiquement à partir du fichierfilename
. La chaînefilename
spécifie le fichier à charger pour obtenir la vraie définition de la fonction.Si
filename
ne contient ni un nom de dossier, ni les suffixes .el ou .elc, cette fonction ajoute un de ces suffixes, et ne chargera pas à partir d’un fichier dont le nom est justefilename
sans suffixe. (La variableload-suffixes
spécifie les suffixes nécessaires.)L’argument
docstring
est la chaîne contenant la doc de la fonction. Mettre cette documentation permet de la regarder sans charger la vraie définition. Normalement, elle devrait être identique à celle de la définition de la fonction. Si ce n’est pas le cas, la doc de la définition de la fonction prendra effet quand elle sera chargée.Si
interactive
est non-nil, la fonction peut être appelée interactivement. Cela permet à la complétion dans M-x de marcher sans charger la vraie définition de la fonction. La vraie façon dont la fonction est interactive est inutile, sauf si l’utilisateur appelle vraiment la fonction, et dans ce cas la vraie définition est chargée.Il est possible d’autoloader les macros et raccourcis clavier comme les fonctions ordinaires. Mettre
macro
danstype
si la fonction est en fait une macro,keymap
si c’est un raccourci clavier.Si
function
a déjà une définition qui est non vide et qui n’est pas un objet autoload, la fonction ne fait rien et retournenil
. Sinon, elle construit un objet autoload, et le met en tant que définition de la fonctionfunction
. - Function:
autoloadp object
Cette fonction retourne non-nil si
object
est un objet autoloadé.Le fichier autoloadé contient généralement d’autres définitions et peut faire des
require
ouprovide
. Si le fichier n’est pas complétement chargé (à cause d’une erreur dans l’évaluation de son contenu), toutes les définitions des fonctions etprovide
qui sont apparus dans le chargement sont défaits. Ceci est fait pour s’assurer que la prochaine tentative d’appel à une fonction autochargée de ce fichier essayera à nouveau de charger le fichier pour être sûr que les fonctions marchent.Si le fichier autochargé échoue à définir la fonction ou macro Lisp désirée, alors une erreur est signalée « Autoloading failed to define function function-name ».
(La suite concerne moins le sujet, mais c’est intéressant, donc je mets pour me souvenir.)
Un commentaire magique
autoload
(souvent appeléautoload cookie
) est composé de;;;###autoload
, sur une ligne, tout seul, juste avant la vraie définition de la fonction. La commande M-x update-file-autoloads écrit l’appel autoload correspondant dansloaddefs.el
. (La chaîne commentaire et le fichier peuvent être changés, voir plus bas.) Construire Emacs chargeloaddefs.el
et appelleautoload
. M-x update-directory-autoloads est encore plus puissant ; ça met à jour les autoloads pour tous les fichiers dans le dossier courant.Le même commentaire magique peut copier n’importe quel type de form dans
loaddefs.el
. La form qui suit le commentaire magique est copié tel quel, sauf si c’est une des forms que autoload gère différemment (par exemple en convertissant en appelautoload
) :Les définitions des objets fonction :
defun
etdefmacro
[comme on vient de voir pour ceux qui suivent] ; et aussicl-defun
,cl-defmacro
etdefine-overloadable-function
.Les définitions des major/minor modes :
define-minor-mode
,define-globalized-minor-mode
,define-generic-mode
,define-derived-mode
,easy-mmode-define-minor-mode
,easy-mmode-define-global-mode
,define-compilation-mode
, etdefine-global-minor-mode
.D’autres types de définition :
defcustom
,defgroup
,defclass
, etdefine-skeleton
.On peut aussi utiliser un commentaire magique pour exécuter une form au moment de la construction sans l’exécuter quand le fichier lui-même est chargé. Pour ce faire, écrire la form sur la même ligne que le commentaire magique. Puisque c’est un commentaire, ça ne fait rien quand on charge le fichier source ; mais M-x update-file-autoloads le copie dans
loaddefs.el
, où il sera exécuté lors de la construction d’Emacs.Un exemple de fonction avec le commentaire magique :
;;;###autoload (defun doctor () "Switch to *doctor* buffer and start giving psychotherapy." (interactive) (switch-to-buffer "*doctor*") (doctor-mode))
Ce qui est écrit dans loaddefs.el
:
(autoload (quote doctor) "doctor" "\ Switch to *doctor* buffer and start giving psychotherapy. \(fn)" t nil)
Si on a écrit une définition de fonction avec une macro qui n’est
pas celle utilisée d’habitude (par exemple mydefunmacro
),
l’utilisation d’un commentaire magique normal copierait toute la
définition dans loaddefs.el
(puisque ce n’est pas une des
exceptions vues précédemment). Ce n’est pas ce que l’on souhaite.
Pour mettre le bon appel autoload
dans loaddefs.el
, il faut
plutôt écrire :
;;;###autoload (autoload 'foo "myfile") (mydefunmacro foo ...)
Comme dit précédemment, on peut utiliser une chaîne différente
pour le cookie autoload et quand même avoir l’appel autoload
correspondant écrit dans un fichier différent de loaddefs.el
.
- Variable:
generate-autoload-cookie
La valeur de cette variable doit être une chaîne dont la syntaxe est une commande Lisp. M-x update-file-autoloads copie la form Lisp qui suit le cookie dans le fichier autoload qu’il génère.
- Variable:
generated-autoload-file
La valeur de cette variable nomme un fichier Emacs Lisp où les appels
autoload
doivent aller (par défautloaddefs.el
)Pour charger explicitement la bibliothèque spécifiée par un objet autoload, on peut utiliser la fonction :
- Function:
autoload-do-load autoload &optional name macro-only
Cette fonction effectue le chargement spécifié par
autoload
, que devrait être un objet autoload.
Repeated Loading: Precautions about loading a file twice.
Comme le dit le titre. Intéressant, mais pas pour notre problème.
Named Features: Loading a library if it isn't already loaded.
provide
et require
sont une autre façon de charger
automatiquement des fichiers. Le chargement automatique est
déclanchée en appelant une fonction particulière, mais une
feature est chargée la première fois qu’un autre programme la
demande, par son nom.
Un nom de feature est un symbole qui représente une collection de
fonctions, variables, etc. Le fichier qui les définit doit faire un
provide
de la feature
.
Un autre programme qui les utilise peut s’assurer qu’elles sont
définies en faisant un require
de la feature
. Cela charge le
fichier de définitions s’il n’était pas déjà chargé (en regardant
la variable globale features
). Si le fichier n’a pas d’appel
« haut niveau » à provide
, require
signale une erreur.
Where Defined: Finding which file defined a certain symbol.
Avec la fonction symbol-file
(qui cherche dans load-history
).
(Par exemple, évaluez (C-x e derrière la parenthèse fermante)
dans un buffer (symbol-file 'emacs-lisp-mode)
ou (symbol-file
'split-window)
.)
Unloading: How to "unload" a library that was loaded.
unload-feature feature
(qui s’aide lui aussi de load-history
)
« décharge » la librairie qui fait un provide feature
. Ça enlève
les définitions des fonctions, macros… crées par des defun
,
defalias
, defsubst
, defmacro
, et restaure les autoloads.
Hooks for Loading: Providing code to be run when particular libraries are loaded.
On peut demander à ce que du code soit exécuté chaque fois qu’Emacs
charge une bibliothèque, en utilisant la variable
after-load-functions
:
— Variable: after-load-functions
Ce hook est lancé après le chargement d’un fichier. Chaque fonction dans le hook est appelé avec un seul argument, le nom avec chemin absolu du fichier qui vient d’être chargé.
Si on veut que du code soit exécuté quand une bibliothèque en
particulier est chargée, il faut utiliser eval-after-load
:
— Function: eval-after-load library form
Cette fonction évalue form
à la fin du chargement du fichier
library
, chaque fois que library
est chargée. Si elle est déjà
chargée, elle évalue form
immédiatement. Par exemple :
(eval-after-load "edebug" '(def-edebug-spec c-point t))
Normalement, les programmes Lisp bien faits ne devraient pas
utiliser eval-after-load
. Si on a besoin d’examiner et
d’initialiser des variables définies dans une autre bibliothèque
(celles définies pour un usage extérieur à la bibliothèque), on
peut le faire immédiatement. Il n’y a pas besoin d’attendre qu’une
bibliothèque soit chargée. Si on a besoin d’appeler des fonctions
définies dans cette bibliothèque, il faut charger la bibliothèque
(de préférence avec require
).
— Variable: after-load-alist
Contient une alist construite par eval-after-load
, contenant les
expressions à évaluer quand certaines bibliothèques sont chargées.
En bref
Pour charger un fichier (et évaluer ce qu’il y a dedans), on utilise
load
. Mais, pour dire à emacs « Hey, la fonction foo
est dans le
fichier bar.el
, mais tu charges (c’est-à-dire évalues) le fichier
qui contient la fonction que quand t’en as vraiment besoin. », et
ainsi pouvoir utiliser foo
sans charger le fichier, on utilise
autoload
. Par exemple,
(autoload 'foo "bar" "Some docstring." t)
dans le .emacs
, va dire que la fonction php-mode
se trouve dans un
fichier php-mode
(avec extension .el
ou .elc
).
De plus, si dans un fichier « standard » il y a des lignes
;;;###autoload
, alors pas besoin d’exécuter des (autoload ...)
, le
fichier loaddefs.el
contient certainement l’appel qui va bien.
Si par contre c’est votre fichier, et que vous voulez ajouter les
fonctions qui suivent les ;;;###autoload
à loaddefs.el
, il faut
appeler update-file-autoloads
(ou update-directory-autoloads
).
Comment est choisi le mode d’un fichier
Choosing-Modes (manuel emacs) Auto-Major-Mode (manuel elisp)
Quand on ouvre un fichier, avec find-file fichier
ou recover-file
,
les fonctions appellent normal-mode fichier
(dans files.el
).
normal-mode fichier
appelle fundamental-mode
sur le buffer puis
appelle set-auto-mode
.
Quand on regarde C-h f set-auto-mode :
La fonction cherche un mode de plusieurs façons :
- Elle cherche un
-*-foo-mode-*-
(voir C-h f set-auto-mode-1) dans le buffer. - Si pas trouvé, cherche un
#!/
à la première ligne (en fait C-h v auto-mode-interpreter-regexp pour être exact). - Si pas trouvé, cherche une regexp pour la première ligne du buffer
(dans C-h v magic-mode-alist (défaut à vide)). Par exemple
("<\\?xml " . xml-mode)
dit que si la première ligne commence par<\\?xml
, on passe enxml-mode
. - Si pas trouvé, cherche une regexp sur le nom de fichier, souvent
l’extension (dans C-h v auto-mode-alist (case-sensitive, puis
insensitive)). Par exemple
("\\.svgz?\\'" . xml-mode)
dit que si le fichier se termine par.svg
ou.svgz
, on passe enxml-mode
. - Si pas trouvé, cherche une regexp pour la première ligne du buffer (dans C-h v magic-fallback-mode-alist).
- Si toujours pas trouvé, on appelle
set-buffer-major-mode
qui dit que :- si le buffer est
*scratch*
,initial-major-mode
; - sinon
major-mode
(c’est-à-direfundamental-mode
par défaut).
- si le buffer est
La plupart du temps, une ligne (add-to-list 'auto-mode-alist
'("\\.[ch]\\'" . c-mode))
sera présente dans le fichier (précédée ou
non d’un commentaire magique).
Bonus
Specifying-File-Variable (manuel emacs)
Le -*-
ne sert en fait pas qu’à mettre le mode. On peut aussi mettre
des variables spécialement pour un fichier. (Pour tous les fichiers
d’un dossier, c’est possible aussi, avec un fichier .dir-locals.el
Directory-Variables (manuel emacs).)
Par exemple,
;; -*- mode: Lisp; fill-column: 75; comment-column: 50; -*-
mettra en mode Lisp et instanciera les deux variables. (Plutôt que d’éditer à la main, on peut utiliser M-x add-file-local-variable-prop-line).
Normalement, c’est sur la première ligne, mais pour les scripts shell (entre autres) où la première ligne sert à connaître l’interpréteur, il peut être sur la seconde ligne.
Ces variables peuvent également être définies à la fin du fichier (avec M-x add-file-local-variable par exemple) sous forme de liste :
/* Local Variables: */ /* mode: c */ /* comment-column: 0 */ /* End: */
La liste doit commencer par Local Variables:
et se terminer par
End:
. Emacs reconnaît automatiquement le préfixe (et comme ici,
éventuellement suffixe) en cherchant autour Local Variables:
.
Pour activer un mode mineur, il faut utiliser eval:
:
;; Local Variables: ;; eval: (eldoc-mode) ;; eval: (font-lock-mode -1) ;; End:
Comme ça peut être dangereux, Emacs peut demander si on veut vraiment les utiliser (Safe-File-Variables (manuel emacs), C-h v safe-local-variable-values).
Hooks
Les hooks (manuel elisp) sont des variables où l’on peut stocker une ou des fonctions à appeler pour une occasion particulière. Emacs permet ainsi de modifier le comportement de certaines fonctions.
Après avoir chargé un fichier, le mode est choisi, puis appelé. Pour
ajouter des fonctions ou appeler des modes mineurs sur ces fichiers,
on peut donc utiliser les hooks. Généralement pour chaque mode, il
existe un hook qui est exécuté après le chargement du mode : pour
nomdumode-mode
il y a nomdumode-mode-hook
. La dernière chose qu’un
major-mode
fait, c’est appeler run-mode-hooks
. Cette fonction
lance change-major-mode-after-body-hook
, nomdumode-mode-hook
puis
after-change-major-mode-hook
.
Si un mode dérive d’un autre, le -mode-hook
du parent est d’abord
exécuté. Du coup, pour changer tous les modes de programmation, il
suffit d’ajouter une fonction à prog-mode-hook
.
Setting-Hooks (manuel elisp)
Un exemple qui utilise le mode hook pour mettre passer en Auto Fill
mode
quand on passe en mode Lisp Interaction
:
(add-hook 'lisp-interaction-mode-hook 'auto-fill-mode)
Normalement, la fonction que l’on ajoute au hook ne prend pas d’argument, mais il est possible de contourner cela avec les fonctions lambda (ModeHooks (emacswiki)) :
(add-hook 'text-mode-hook (lambda () (set-fill-column 72))) (add-hook 'text-mode-hook (lambda () (column-number-mode 1)))
Hooks-for-Loading (manuel elisp)
(Je reprends ce que je dis plus haut, en ajoutant des exemples.)
On peut également demander à ce que du code soit exécuté à chaque fois
qu’Emacs charge une bibliothèque avec le hook after-load-functions
(attention, chaque fonction du hook est appelée avec un argument : le
chemin complet du fichier qui vient d’être chargé).
Si on veut que le code soit exécuté à chaque fois qu’une bibliothèque
est chargée, il faut utiliser eval-after-load
. La fonction évalue le
code à la fin de chaque chargement de la bibliothèque. Si elle est
déjà chargée, le code est exécuté immédiatement.
Par exemple, pour charger la bibliothèque my-foo-config
après que
file-foo.txt
ait été chargé :
(eval-after-load "file-foo.txt" '(load "my-foo-config"))
Pour exécuter la fonction foo-bar
après avoir chargé le mode
foobar
:
(eval-after-load "foobar-mode" '(foo-bar"))
Différences
On peut parfois utiliser indifférement l’une ou l’autre des méthodes.
Mais, le code de eval-after-load
sera exécuté seulement une fois, et
donc est généralement utilisé pour par exemple instancier des valeurs
globales par défaut ou configurer un keymap par défaut pour un certain
mode. Dans le code du eval-after-load
, il n’y a pas non plus de
notion de buffer courant.
Les nomdumode-mode-hooks
, eux, sont exécutés pour chaque buffer dans
lequel le mode sera activé.
Conclusion
Que fait le code du début
Reprenons notre bout de code du début :
(autoload 'php-mode "php-mode" "Major mode for editing php code." t) (add-to-list 'auto-mode-alist '("\\.php$" . php-mode))
La première ligne indique donc à Emacs où chercher la fonction
php-mode
– dans un fichier php-mode.el
(ou .elc
) – mais que pour
le moment, ce n’est pas la peine de charger et d’évaluer le fichier
(et donc la fonction).
La deuxième indique que quand Emacs va ouvrir un fichier, s’il n’a pas
trouvé de ligne contenant -*-foo-mode-*-
, de shebang (#!
)
indiquant quel mode charger, et que le fichier se termine par .php
,
alors, il faut lancer la fonction php-mode
.
Ces lignes permettent donc de (et sont nécessaire pour) passer en
php-mode
quand on ouvre un fichier dont l’extension est .php
sans
forcément charger le fichier php-mode.el
.
C’est plutôt pas mal, sauf que, ces lignes sont sans doute totalement
inutiles… Pour s’en rendre compte, il suffit de lancer Emacs sans
fichier de config avec -q
ou --no-init-file
(voire -Q
qui fait
--no-init-file --no-site-file --no-splash
), et de regarder si le
fichier qu’on veut ouvrir se met bien dans le bon mode. Ou alors, de
regarder auto-mode-alist
, ainsi que loaddefs.el
.
Comment configurer un mode
En utilisant les hooks. La façon la plus simple est d’utiliser :
(add-hook 'text-mode-hook 'auto-fill-mode)
Si on veut utiliser une fonction avec argument, il faut passer par des fonctions lambda :
(add-hook 'latex-mode-hook (lambda () (auto-fill-mode -1)))
Voilà, je ne sais pas si c’est plus clair pour vous, mais en tout cas,
ça m’a permis d’en apprendre un peu plus sur Emacs. (Et encore, je ne
vous ai pas parlé de hack-local-variables-hook
, du fichier
.dir-locals.el (manuel emacs), de…
(Merci aux relecteurs.)
Edit dans dired/occured = awesome
Voici des exemples qui font que je ne pourrais pas me passer d’Emacs tant il me facilite la vie. (Attention, certaines des fonctionnalités que je vais utiliser ne marchent qu’avec Emacs > 24.)
dired mode
Mise en place des exemples
Dans une console, tapez les commandes
mkdir -p /tmp/testEmacs{1..2} && cd /tmp/testEmacs1 for i in {01..10};do dd if=/dev/urandom count=$((RANDOM%10+1)) bs=1024 | base64 > fic$i;done touch /tmp/testEmacs2/fic{{01..10},{03..05}.bck}
qui vont créer dix fichiers contenant du texte aléatoire dans le
dossier /tmp/testEmacs1
et des fichiers dont certains possèdent une
sauvegarde.
Dans Emacs, en tapant C-x f /tmp/testEmacs1 on se trouve dans le
dossier en mode Dired
.
Le mode édition ou wdired mode
Renommer les gros fichiers
Le but ici va être de renommer les fichiers de taille supérieur à 10000, pour par exemple vérifier plus tard leur contenu, effectuer des remplacements à l’intérieur des fichiers, ou juste pour l’exemple en fait…
Dans un buffer en mode dired
, il est possible de passer en mode
édition avec C-x C-q (en fait on passe en wdired-mode
(pour
Writable Dired)). Cela permet entre autres choses de renommer les
fichiers ou changer leur permission.
Pour marquer nos fichiers, il est plus simple de les trier par taille.
Pour cela un petit C-u s nous permet de spécifier comment trier les
fichiers. En ajoutant S aux options du ls
qui s’affichent, on a
donc les plus gros fichiers en premiers.
En mode édition (C-x C-q donc), on se met à la fin du premier
fichier, C-spc, on descend jusqu’au fichier voulu, on insère un
rectangle
avec C-x r t .aVerifier et les fichiers sont renommés. Il ne
reste plus qu’à valider avec un C-c C-c.
Remplacer les .bck
Pour ce deuxième exemple (C-x f /tmp/testEmacs2), on a un certain
nombre de fichiers qui possède une sauvegarde (un fichier .bck
). On
veut les changer : le fichier ficXY
deviendra ficXY.bck
et
inversement.
Pour ça, je propose la macro suivante :
- C-x C-q on passe en mode édition
- F3 début d’enregistrement de la macro
- C-s .bck pour chercher la prochaine sauvegarde
- C-p .bck pour renommer le fichier sans extension
- C-n C-u BCKSPC pour renommer la sauvegarde
- F4 pour terminer la macro
- M-0 F4 pour exécuter la macro sur les autres fichiers
- C-c C-c pour valider
Le .bck
ne nous plait pas et on veut renommer en .save
?
- C-x C-q on passe en mode édition
- M-< on remonte au début du fichier
- C-M-% .bck$ .save pour modifier l’extension
.bck
en.save
- ! pour renommer tous les fichiers
- C-c C-c pour valider
occur mode
(C’est cette partie qui nécessite un Emacs récent.)
Présentation
Vu que je n’ai pas encore parlé d’occur
, je fais une rapide
présentation :
M-s o lance la commande occur
et demande une regexp. Elle affiche
dans un buffer *Occur*
les lignes qui contiennent la regexp. Un
argument permet de définir le contexte (comme grep -C2
par exemple).
multi-occur
, respectivement multi-occur-in-matching-buffers
,
permet de montrer les lignes dans les buffers que l’on a renseigné un
par un, resp. par une regexp (utilisez . pour tous les buffers
donc). Pour faire pareil avec les buffers marqués dans la liste des
buffers (C-x C-b), il existe Buffer-menu-multi-occur
.
Dans la fenêtre qui s’ouvre, on a le nombre de concordances avec le nom du buffer. Si on clique sur la ligne, on va dans le buffer d’origine.
C’est donc pratique pour par exemple avoir un index des fonctions d’un fichier (M-s o function), lister tous les endroits où l’on a une adresse http (M-s o http), etc.
Le mode édition ou occur-edit mode
À partir de la version 24, un appui sur e perment de passer en mode
Occur-Edit
. Dans ce mode, les changements dans le buffer sont aussi
appliqués dans le buffer d’origine. C’est un bon moyen plus visuel
pour faire du remplacement sélectif.
Par exemple, dans un buffer, on a les lignes suivantes :
[...] variable 1 valeur: chose 2 [...] variable x valeur: chose y [...] variable 3 valeur: chose 4 [...] variable x valeur: chose y [...] variable 4 valeur: chose 4 [...]
Et on veut remettre la valeur correspondant à la variable sauf dans le cas des variables x.
Bien entendu, il est possible de faire ça en utilisant des regexps/macro/fonctions lisp. Mais il y a aussi moins « prise de tête ».
Pour notre problème, M-- M-1 M-s o valeur permet d’afficher les lignes contenant « valeur » et celle d’avant.
En appuyant sur e on passe en mode édition, et il est facile de changer uniquement les lignes qu’il faut (comme on le ferait dans le buffer d’origine).
Pour sortir du mode édition, un C-c C-c, puis q pour quitter le mode occur.
Si l’on veut supprimer « chose » et garder uniquement le numéro (pas
quand c’est chose y
donc) :
- M-s o valeur: chose pour afficher les bonnes lignes
- C-x o pour passer dans le buffer
*occur*
- e pour passer en mode édition
- M-x flush-lines chose y pour supprimer du buffer
*occur*
les lignes que l’on ne veut pas changer - M-% chose SPC ENTER ENTER ! pour supprimer tous les « chose﹏ »
- C-c C-c puis q pour sortir du mode étition et quitter occur.
Le buffer ressemble maintenant à :
[...] variable 1 valeur: 1 [...] variable x valeur: chose y [...] variable 3 valeur: 3 [...] variable x valeur: chose y [...] variable 4 valeur: 4 [...]
Autre exemple :
variable 1 valeur: bépo [...] variable 2 valeur: auie [...] variable 3 valeur: êàyx [...] variable 4 valeur: vdlj [...] variable 5 valeur: tsrn [...]
et on veut décaler les valeurs (variable 2
aura pour valeur bépo
,
etc.).
Pour cela, M-s o valeur: suivi de e pour passer en mode
occur-edit
. Puis on kill bépo
et on se place au début de auie
.
On est prêt pour notre macro :
- F3
- M-d, on kill le mot (ou C-k si plusieurs mots)
- C-y M-y on colle le précédent1
- C-x C-x pour revenir où on était (au début du mot)
- C-n pour passer à la ligne suivante
- F4
Alors oui, on peut se passer d’occur-edit
en faisant un C-s valeur:
SPC ENTER à la place de C-n. Mais souvent, il y a un valeur:
dans
les [...]
que je ne veux pas changer ; plutôt que de faire du F4
au coup par coup (ou de me rendre compte du changement non voulu trop
tard), il est plus simple, je trouve, de supprimer la ligne dans
*occur*
, puis d’appliquer la macro avec un M-0 F4.
À lire
- Dired Shell Commands: The find & xargs replacement
(MasteringEmacs.com) : Mickey nous montre comment faire un
find ... -exec
oufind ... | xargs
avecdired-x
(qu’il faudra que j’essaie un de ces quatre…). - Episode 13: multiple-cursors (Emacs Rocks!) : une vidéo dans laquelle Magnar Sveen renomme des fichiers avec multiple-cursors.el (github) (plutôt que d’utiliser un rectangle).
- In Emacs, How to replace only on matching lines
(stackoverflow.com) : un exemple d’utilisation du mode
occur-edit
qui ressemble finalement au mien.
Un peu de typographie et marquer les raccourcis clavier dans org-mode
Utilisant la disposition de clavier bépo, et soucieux d’écrire le plus
correctement possible, j’ai pris l’habitude de mettre des espaces
insécables lorsque c’est nécessaire (même si, je l’avoue, je n’utilise
pas les espaces fines… désolé). Depuis plusieurs jours, j’utilise
également les apostrophes courbes (!wfr) et plus celles qui se trouve
sur la touche 4
des claviers azerty, des droites : l’apostrophe
courbe
vs l'apostrophe droite
.
Ajouter des caractères autorisés à org-emphasis-regexp-components
Le souci avec org-mode
, c’est que mettre des espaces insécables
après des signes d’emphases (mise en gras *
, italique /
, etc.)
n’est pas possible par défaut : « =chose=﹏:
» où ﹏ est une espace
insécable n’affichera pas « chose
: », mais s’affichera tel quel.
Dans mes précédents articles, je remplaçais l’espace insécable par une
espace « normale ». Et c’est quelque chose que je ne voulais pas. J’ai
donc regardé dans le code, et dans org.el
est trouvé la variable
org-emphasis-regexp-components
. Malheureusement, elle est précédée
du commentaire suivant :
;; This used to be a defcustom (Org <8.0) but allowing the users to ;; set this option proved cumbersome. See this message/thread: ;; http://article.gmane.org/gmane.emacs.orgmode/68681
Comme j’utilise maintenant une version ≥ 8.0, je suis obligé de la
modifier « en dur » dans un fichier org-conf.el
(ou dans le
.emacs
, mais je vais en fait faire plusieurs modifications ; je crée
un fichier à part pour ma configuration d’org-mode). La documentation
de la variable indique clairement les différents parties : les
caractères possibles avant le signe de début, après le signe le fin,
interdits après le signe de début/avant le signe de fin, etc.
Ce qui m’intéresse, ce sont les signes autorisés avant et après. Voilà donc ce que j’ai dans mon fichier :
;on ajoute _ et … dans post, ’ dans pre (defvar org-emphasis-regexp-components '(" \t ’('\"{" "- \t ….,:!?;'\")}\\" " \t\r\n,'" "." 1) "support for ' ', '…' and '’'")
Mes modifications sont les deux caractères qui suivent la tabulation.
Indiquer les appuis sur des touches
Une autre modification que je souhaitais depuis quelques temps, est
celle de séparer la façon dont je mets en avant les noms de fonctions
des raccourcis clavier. Avant, j’utilisais (essayais d’utiliser) ~
(verbatim) pour marquer les raccourcis, et =
(code) pour les
fonctions. Mais cela ne me satisfaisait pas. Et puis, j’ai découvert
la balise <kbd> (w3.org), et je me suis dit que j’allais utiliser ça
pour l’export. Sauf que je voulais garder la signification de ~
et
=
. Je me suis dit qu’il me fallait un nouveau marqueur. J’utilise
dorénavant ‰
pour mettre les commandes qu’il faut taper. ‰C-x C-s‰
sera alors exporté en <kbd>C-x C-s</kbd>
. Il faudrait que ce soit
<kbd><kbd>C</kbd>-<kbd>x</kbd> <kbd>C</kbd>-<kbd>s</kbd></kbd>
pour
que ce soit plus juste, mais je m’en passerai pour l’instant.
J’avais dans l’idée de modifier mon css pour que le raccourci apparaisse avec un beau petit cadre autour. Et puis je me suis dit que ce serait sympa d’avoir la même chose dans Emacs. Du coup, je me suis créé une face pour cela :
(defface my-face-org-keystroke '((t (:inherit shadow :box (:line-width -2 ;neg. in order to keep the same size of lines :color "grey75" :style pressed-button)))) "Face for keystrokes" :group 'org-faces)
Pour indiquer que ‰
est un marqueur, il faut customizer la variable
org-emphasis-alist
. La mienne vaut maintenant :
(("*" bold) ("/" italic) ("_" underline) ("=" org-code verbatim) ("~" org-verbatim verbatim) ("+" (:strike-through t)) ("‰" my-face-org-keystroke verbatim));cette ligne correspond à mon ajout
Il faut maintenant définir/modifier plusieurs fonctions pour
qu’org-mode
se comporte comme attendu lors de l’export.
Dans mon org-conf.el
, il me faut charger ox.el
sous peine d’avoir des erreurs :
(require 'ox) ;;otherwise org-element--parse-objects: Symbol's function definition is void: org-element-my-object-keystroke-parser
J’ai ensuite défini les fonctions qui existent pour bold
ou code
et modifié celles où apparaissent tous les objets concernés par
l’export :
;creation (defun org-html-keystroke (keystroke contents info) "Transcode KEYSTROKE from Org to HTML. CONTENTS is nil. INFO is a plist holding contextual information." (format (or (cdr (assq 'my-object-keystroke org-html-text-markup-alist)) "%s") (org-html-encode-plain-text (org-element-property :value keystroke)))) ;creation (defun org-element-my-object-keystroke-parser () "Parse code object at point. Return a list whose CAR is `my-object-keystroke' and CDR is a plist with `:value', `:begin', `:end' and `:post-blank' keywords. Assume point is at the first tilde marker." (interactive) (save-excursion (unless (bolp) (backward-char 1)) (looking-at org-emph-re) (let ((begin (match-beginning 2)) (value (org-match-string-no-properties 4)) (post-blank (progn (goto-char (match-end 2)) (skip-chars-forward " \t"))) (end (point))) (list 'my-object-keystroke (list :value value :begin begin :end end :post-blank post-blank))))) ;creation (defun org-element-my-object-keystroke-interpreter (keystroke contents) "Interpret KEYSTROKE object as Org syntax. CONTENTS is nil." (format "‰%s‰" (org-element-property :value keystroke))) ;modification (defconst org-element-object-successor-alist '((subscript . sub/superscript) (superscript . sub/superscript) (bold . text-markup) (code . text-markup) (italic . text-markup) (strike-through . text-markup) (underline . text-markup) (verbatim . text-markup) (entity . latex-or-entity) (latex-fragment . latex-or-entity) (my-object-keystroke . text-markup)) "Alist of translations between object type and successor name. Sharing the same successor comes handy when, for example, the regexp matching one object can also match the other object.") ;modification (defconst org-element-all-objects '(bold code entity export-snippet footnote-reference inline-babel-call inline-src-block italic line-break latex-fragment link macro radio-target statistics-cookie strike-through subscript superscript table-cell target timestamp underline verbatim my-object-keystroke) "Complete list of object types.") ;modification (defun org-element-text-markup-successor () "Search for the next text-markup object. Return value is a cons cell whose CAR is a symbol among `bold', `italic', `underline', `strike-through', `code' and `verbatim' and CDR is beginning position." (save-excursion (unless (bolp) (backward-char)) (when (re-search-forward org-emph-re nil t) (let ((marker (match-string 3))) (cons (cond ((equal marker "*") 'bold) ((equal marker "/") 'italic) ((equal marker "_") 'underline) ((equal marker "+") 'strike-through) ((equal marker "~") 'code) ((equal marker "=") 'verbatim) ((equal marker "‰") 'my-object-keystroke) ;a ajouter (t (error "Unknown marker at %d" (match-beginning 3)))) (match-beginning 2))))))
Et voilà, on a ce qu’il faut pour exporter ‰C-x C-s‰
en « C-x
C-s » et pour que dans Emacs ça y ressemble également.
Reste maintenant l’export via C-c C-e. On peut redéfinir le backend
html en copiant/collant les lignes d’ox-html.el
qui commencent par
(org-export-define-backend 'html
et en ajoutant
(my-object-keystroke . org-html-keystroke)
dans la liste qui va
bien. Mais ça fait un peu long. Et puis on perd l’export par défaut.
J’ai préféré définir mon propre export, vu que ce n’est pas très difficile :
(org-export-define-derived-backend 'my-html 'html :translate-alist '((my-object-keystroke . org-html-keystroke)) :menu-entry ' (?h 1 ((?r "my-html" org-html-export-to-my-html)))) (defun org-html-export-to-my-html (&optional async subtreep visible-only body-only ext-plist) "Export current buffer to a HTML file. Return output file's name." (interactive) (let* ((extension (concat "." org-html-extension)) (file (org-export-output-file-name extension subtreep)) (org-export-coding-system org-html-coding-system)) (org-export-to-file 'my-html file async subtreep visible-only body-only ext-plist))) (defun org-html-publish-to-my-html (plist filename pub-dir) "Publish an org file to my-html. Return output file name." (org-publish-org-to 'my-html filename (concat "." (or (plist-get plist :html-extension) org-html-extension "html")) plist pub-dir)) (defun org-html-convert-region-to-my-html () "Assume the current region has org-mode syntax, and convert it to HTML. This can be used in any buffer. For example, you can write an itemized list in org-mode syntax in an HTML buffer and use this command to convert it." (interactive) (org-export-replace-region-by 'my-html))
Je n’ai plus qu’à faire un C-c C-e h r pour exporter comme il faut.
Il m’a fallu également modifier ma configuration pour publier, mais vu que je suis en train de faire des modifications, j’y reviendrai un autre jour.
Il va falloir maintenant que je reprenne mes anciens articles pour
changer les ~
par des ‰
, mais ça, ça viendra plus tard :þ
Une espace une tabulation
Aujourd'hui, je vais parler des espaces dans Emacs, mais pas que (oui, ces temps-ci, ce sera beaucoup, beaucoup d'Emacs dont il sera question). Et oui, les espaces dont je vais parler, ce sont les espaces aux féminins : le caractère typographique, représenté par un espace (au masculin celui-ci) entre les mots.
Pour voir les espaces que vous avez tapées, et savoir si un espace est constituée d'une ou plusieurs espaces, voire de tabulations, il existe un mode pour cela : M-x whitespace-mode
permet de voir tout ce qui est d'habitude invisible (ou presque).
Les espaces seront alors représentées par des ·
(ou seront en couleur si la ligne ne dépasse pas du buffer), les fins de lignes par $
, les espaces (qui devraient être fines) insécables par ¤
, les tabulations seront en couleur, etc.
Bon, c'est pas le truc dont je vais me servir souvent. Par contre, dans la bibliothèque du mode (find-library whitespace
si vous avez installé le paquet emacs2x-el
), il y a tout un tas de fonctions liés aux espaces en général, comme whitespace-cleanup
qui se charge des :
- lignes vides en début de buffer ;
- lignes vides en fin de buffer ;
- 8 espaces ou plus en début de lignes ;
- espaces avant les tabulations ;
- espaces et tabulations en fin de ligne ;
- 8 espaces ou plus après une tabulations.
(extrait de l'aide de la fonction, C-h f whitespace-cleanup
).
Bref, de quoi faire du ménage si vous n'avez pas fait C-x C-o
à la fin de votre fichier par exemple (voir précédemment).
La bibliothèque propose tout un tas d'autres fonctions, qui sont grandement customizable, et je vous invite à y jeter un coup d'œil. Si le whitespace cleanup est trop radical pour vous, ce hook est plutôt sympa :
(add-hook 'before-save-hook 'delete-trailing-whitespace)
Raccourcis utilisés
Pour entrer un caractère utf-8 avec son code hexadécimal (ou son nom) C-x 8 Enter
puis le code.
Relancer une précédente commande en ksh
Pour le boulot, on fait parfois des sudo su - someUser
avec someUser qui est en ksh
et qui en plus est en mode vi (Adieu C-r
, C-p
, C-k
, C-e
. Bonjour /
, Esc-k
, dd
, A
). Du coup, comme il est « partagé », je ne mets pas de bash par défaut ni de set -o emacs
(sympa hein ‽). Et au final, je m’y retrouve plutôt bien. Il n’y a pas tellement de différences entre ksh et bash.
Sauf une chose dont je me sers au final assez souvent, l’history expansion (avec le fameux sudo !!
par exemple, mais aussi !!:gs:/foo/bar/
). Mais en cherchant un peu, il y a quelque chose qui y ressemble vaguement : la commande r
. Ça n’est pas la panacée, mais c’est un début : ça permet de relancer la dernière commande qui commence par l’argument de r
.
$> echo "toto" $> touch toto $> r e #lance echo "toto" $> r t #lance touch toto
Avec un argument entier, cela fait la même chose que !
en bash : un positif = la nième commande, un négatif = la nième commande avant celle-ci.
$> echo "toto" $> touch toto $> r -2 #lance echo "toto"
Et enfin, avec r avant=apres
, on relance la dernière commande en changeant le premier avant
par après
.
$> cp fic1 /tmp/fic1 $> r 1=2 #lance cp fic2 /tmp/fic1
Des raccourcis en vrac
Bon, j’ai tout plein de choses à faire, mais pas de temps. Quelques choses à partager aussi, mais pas de temps non plus. Du coup, je vais essayer de partager moins mais plus fréquemment.
C’est pas gagné…
En attendant, voici des choses que j’ai trouvées récemment, sans rapport, et sans transition.
M-1 C-x $ / C-x $
Le « code folding » du pauvre (trouvé sur un vieil article d’emacs.wordpress.com). C-x $
appelle la fonction set-selective-display
qui la met dans le premier cas à 1 (dans le second à 0) et n’affiche que les lignes dont l’indentation est >= à 1 (resp. 0).
Bien pratique quand on indente correctement son code pour n’afficher que les définitions de fonctions…
Dans simple.el
Quand on fait comme le suggère l’article précédent C-h k C-x $
, on voit que que la commande est définit dans simple.el
. Et comme je suis curieux, je suis allé y faire un tour. Je vous conseille d’en faire autant (pour cela il faut avoir installé les fichiers emacs23-el (à adapter selon la version)). C’est dans ce fichier que sont définies les fonctions comme beginning-of-buffer
, goto-line
, what-line
, count-lines
, kill-ring-save
, zap-to-char
, toggle-word-wrap
, etc. Voici les fonctions que j’ai trouvées intéressantes :
split-line C-M-o
Le | représente le curseur :
texte :|texte2
Après C-M-o
:
texte curseur:| texte2
Bref, comme C-o
, mais garde la colonne.
delete-indentation M-^
Relie la ligne à la précédente et arrange les espaces à la jointure (plus parlant sur l’alias join-line
). Avec un argument, relie à la suivante :
Les _ représentent des espaces, | le curseur
auie_____ ___au|ie___ ___auie
C-u M-^
auie_____ ___auie_|auie
M-^
auie_|auie_auie
Le mieux étant d’essayer…
delete-blank-line C-x C-o
Plus ou moins comme just-one-space M-spc
mais pour les lignes. (À ce propos,je pense que je vais mettre cycle-spacing
à la place de M-spc
. Mais bon, ça fait partie des choses à faire… Changer certains raccourcis. Je me suis dit ça en voyant certains changements faits par Mickey).
M-x follow-mode
Ou carrément M-x follow-delete-other-windows-and-split
qui splitte la fenêtre et passe en follow-mode
. Les deux fenêtres représentent le même buffer, et l’une suit l’autre. C’est assez sympa comme effet, même si je ne m’en servirai probablement jamais.
Dired : C-x C-q
y u no in C-h m !!??
Je ferai (ou pas) certainement un billet sur les fonctionnalités dont je me sers de ce mode, mais j’ai (re-)découvert via sachachua (je crois, c’était il y a quelques temps), que l’on pouvait passer en mode édition, et donc renommer plein de fichiers facilement. Et quand on fait un C-h m
ce raccourci n’apparaît pas. Pourquoi ‽
occur M-s o
À partir d’emacs24 seulement, e
et on passe en mode edit sur les lignes qui matchent : que du bonheur ! Pareil, un billet à faire tellement c’est pratique…
C-x C-0
, C-x C-=
, C-x C--
, C-x C-+
, text-scale-adjust
Pour augmenter/diminuer la taille de la police du texte du buffer courant.
Footnotes:
J’aurais pu faire l’inverse : coller le premier, puis killer le
second. Mais visiblement, certaines personnes, qui utilisent pourtant
souvent Emacs, n’ont pas pris la peine de faire le tuto (C-h t) et
ne connaissent pas le kill ring
.
Dans Emacs, il existe pour certaines commandes un ring
qui permet de
retrouver d’anciennes valeurs (C-h v -ring TAB). Par exemple
search-ring
garde les 16 (search-ring-max
) dernière recherche, et
quand on fait un C-s, il est possible de faire un M-p ou M-n
pour parcourir cette liste. Quand on met une mark avec C-SPC
(set-mark-command
) elle est mise dans le mark-ring
et il est
possible de revenir aux précédentes avec C-x C-SPC ou C-u C-SPC
(attention, il existe un ring local au buffer, et un global !).
Vous l’avez deviné, c’est la même chose avec le kill-ring
: quand on
utilise C-k, M-d, C-w, etc. on ajoute la ligne/le mot/la région
au kill ring
(avec C-M-w on ajoute la région au dernier élément du
kill-ring
; si on fait deux C-d à la suite, le deuxième mot coupé
est ajouté au premier : le kill-ring
n’a qu’un nouvel élément).
Quand on colle avec C-y on réinsert le kill le plus récent. Si on
fait M-y ensuite, on remonte le kill-ring
. (Il est possible
d’utiliser un argument pour coller le n-ième élément du kill-ring
.
(Et j’aurais également pu éviter le C-x C-x
avec C-u C-y qui colle
en laissant le point (curseur) au début, et la mark à la fin.)
Voir le chapitre Killing and Moving Text (manuel emacs) du manuel pour plus d’infos.
Ce qui est sympa, c’est d’utiliser desktop-save-mode
et sa variable
desktop-globals-to-save
pour enregistrer des rings (par défaut le
search-ring
est sauvé par exemple).
Rien ne sert de modifier startup.el
, le fichier sert
« seulement » à construire les exécutables Emacs DumpingEmacs
(emacswiki). Il est chargé par loadup.el
(qui est en fait la
première chose chargée (source c)) après plusieurs autres
bibliothèques comme :
subr
: qui contient des fonctions lisp commepush
,caar
,last
,add-hook
,with-temp-buffer
,save-window-excursion
, etc.) ;custom
: qui contient le code nécessaire à la déclaration et l’initialisation des options via customize ;window
: qui touche auxwindows
etframes
(delete-other-window
,split-window
,switch-to-buffer
, etc.) ;files
: ce qui touche aux fichiers (find-file
,recover-file
,save-buffer
,write-file
, etc.) ;
C’est un peu compliqué de savoir comment est définit load-path (source c) à la compilation d’Emacs (comme ça dépend de comment ça a été compilé) et donc connaître les additions des répertoires, mais comme les (sous-)dossiers sont ajoutés à la fin, on peut retrouver sa valeur au lancement d’Emacs.