De la couleur dans votre xterm
Malgré tous les efforts de certains projets travaillant sur des environnements dédiés au tout graphique, une certaine majorité des utilisateurs GNU/Linux continue de voir dans la console virtuelle le meilleur moyen de travailler. Souvent, le nouveau venu se jettera avidement sur des applications basées sur Gnome, KDE ou Gnustep, puis s'en détournera peu à peu pour leur préférer des applications en mode texte.
Ceci est bien sûr valable pour la bonne vieille ligne de commande venant au secours du gestionnaire de fichiers encore trop peu efficace, mais également pour tout un tas d'autres logiciels comme les clients mail, les gestionnaires de fichiers et même les navigateurs Web.
Eh oui, console, ligne de commande et terminaux virtuels ne riment pas forcément avec difficulté et laideur ! C'est ce dernier point que nous allons mettre en défaut dans le présent article. Nous allons démontrer qu'il est possible de faire "beau" en mode console, tout en gardant l'atout majeur : la rapidité.
Modifications classiques
Nous considérerons ici que vous êtes à même de modifier les fichiers de configuration de base du système (comme par exemple les préférences de votre shell ou encore les variables d'environnement utiles).
Vous aurez alors sans doute essayé les diverses modifications d'usage comme la console en frame buffer, les remplacements d'xterm (aterm, Eterm, rxvt, etc.), l'essai de différentes polices de caractères ou encore la personnalisation de l'invite du shell.
Mais la personnalisation a malheureusement des limites. Je parle, par exemple, de la personnalisation de l'invite du shell, du ls en couleur, etc. Bien que des applications comme bashish permettant d'utiliser des thèmes facilitent grandement les choses, les obstacles auxquels nous butons sont propres à l'émulateur de terminal. Sous X, il est possible de tirer le meilleur de la carte graphique à l'aide d'une configuration optimale. Selon le matériel (carte et écran), on configure habituellement une résolution entre 1024x768 et 1600x1200 avec une profondeur de couleur de 16 à 32 bits.
16 couleurs ?
Le problème est que l'émulateurs de terminal pour Xwindow ne tire pas avantage de ces capacités (profondeur de couleurs). Plus exactement, il ne s'en sert pas... par défaut. Pour connaître le nombre de couleurs utilisées par votre xterm, utilisez la commande suivante en tant qu'utilisateur root (les manipulations sur xterm qui vont suivre proviennent d'une astuce que Randy Hron a diffusé sur la ML LFS) :
# strings /usr/bin/X11/xterm | grep "^color[0-9]" | sort -tr +1 -n
color0
color1
color2
color3
color4
color5
color6
color7
color8
color9
color10
color11
color12
color13
color14
color15
De 0 à 15, nous avons donc 16 couleurs à notre disposition. Notez que le chemin vers le binaire xterm tel qu'il est donné ici est celui d'une distribution Debian. Un type xterm vous fournira le vôtre. La compilation par défaut d'xterm comprend la gestion de 16 couleurs, mais il est possible de passer outre.
Dans un premier temps, récupérez la dernière version des sources d'xterm (ici la version 158) et désarchivez-la dans un répertoire quelconque. Les sources d'xterm n'utilisent pas autoconf/automake mais l'ancien système de création de Makefile. Placez-vous donc dans le répertoire des sources (normalement xterm-158) et faites :
$ xmkmf
Ceci aura pour effet de créer un Makefile tout neuf. Mais il nous faudra le modifier pour activer la gestion des 256 couleurs. Dans le Makefile, ajoutez -DOPT_256_COLORS concernant les defines UTF8 (UTF8_OPTION). Randy simplifie la tâche en utilisant sed pour ce travail et en ajoutant un nouveau type de terminal pour le termcap/terminfo :
$ sed 's/_WIDE_CHARS/_WIDE_CHARS -DOPT_256_COLORS -DDFT_TERM_TYPE=xterm-color/' Makefile > Makefile~
$ mv Makefile~ Makefile
Vous pouvez, à présent, compiler tranquillement votre nouvel xterm avec un simple make. Notez qu'il ne semble pas être possible de compiler le support 256 couleurs dans celui pour l'UTF8. Avant l'installation, il est fortement conseillé de faire quelques essais afin de vous assurer que tout fonctionne correctement. Dans un premier temps, réutilisons string comme précédemment pour vérifier le nombre de couleurs supportées, mais cette fois, sur le binaire dans le répertoire courant. Vous devrez, en principe, obtenir ceci :
$ strings ./xterm | grep "^color[0-9]" | sort -tr +1 -n
color0
color1
color2
[...]
color252
color253
color254
color255
Nous avons bien 256 couleurs à notre disposition dans ce nouveau binaire. Passez alors en root et renommez votre ancien xterm en xterm.old (ou autre chose) et placez le nouveau binaire en lieu et place de l'ancien.
Utilisation du xterm256
Vous trouverez dans les sources de votre xterm un répertoire vttests contenant un certain nombre de scripts shell et de code Perl permettant de tester les nouvelles fonctionnalités. Lancez donc un xterm comme vous le feriez normalement (nous avons remplacé le binaire), puis testez le plus impressionnant des scripts :
$ ./256color2.pl
Après un petit moment, vous devrez voir apparaître quelque chose d'approchant l'image en figure 1. Vous constaterez par vous-même qu'il s'agit bel et bien de texte et non d'une quelconque autre astuce. Et bien sûr, le plus important : c'est beau :)
En étudiant avec soin le code des différents scripts, nous apprenons la manière d'utiliser les nouvelles couleurs à l'aide des séquences ANSI classiques. Les séquences utilisent des codes jusqu'alors inutilisés. Voici les couleurs et les attributs tels qu'ils sont définis avec une gestion 16 couleurs classique :
Attributs
Valeur
Signification
00
aucun
01
gras
02
pâle ??
03
en évidence ??
04
souligné
05
clignotant
07
inverse
08
caché ??
22
normal
23
non en évidence ??
24
non souligné
25
non clignotant
27
non inverse
Couleurs d'avant-plan
Valeur
Signification
30
noir
31
rouge
32
vert
33
jaune
34
bleu
35
magenta
36
cyan
37
blanc
39
défaut
Couleurs d'arrière-plan
Valeur
Signification
40
noir
41
rouge
42
vert
43
jaune
44
bleu
45
magenta
46
cyan
47
blanc
49
défaut
Nous composons donc une séquence comme ceci :
$ echo -e "e[42;31;1mCOUCOUe[0m"
L'option -e nous permet de demander à la commande echo d'interpréter les séquences d'échappement. e est le caractère ESCAPE débutant toute séquence de ce type. Suivent ensuite les codes concernant les couleurs, ici un texte en gras (1) et rouge (31) sur fond vert (42). La séquence se termine par m. Suit ensuite une chaîne de caractères (COUCOU) et une nouvelle séquence permettant de revenir à la valeur initiale.
Vous remarquerez que dans les tableaux précédents ne figurent pas les codes 38 et 48. Ceux-ci sont justement utilisés pour les séquences permettant d'accéder aux autres couleurs. Considérez le code Perl suivant :
for ($color = 255; $color >= 232; $color--)
print "e[48;5;$colorm ";
print "e[0mn";
Nous créons une boucle affichant à chaque tour la séquence e[48;5;nm suivie de deux espaces. n est une valeur comprise entre 255 et 232. En sortie de boucle, nous n'oublions pas de revenir aux paramètres initiaux. Ce code, avec un xterm classique, ne vous affichera rien du tout puisque la couleur de fond 48 n'existe pas. En revanche, avec le nouvel xterm en 256 couleurs, vous verrez apparaître un magnifique dégradé de 24 couleurs du blanc vers le noir.
Remplacez 48 par 38 et les deux espaces par un caractère quelconque et vous obtiendrez la même chose avec des couleurs d'avant-plan.
Pour manipuler l'ensemble des couleurs, vous n'aurez qu'à analyser les scripts du répertoire vttest. Tout y est quasi clairement indiqué. Les couleurs sont réparties en un cube de 6x6x6.
Mais à quoi peuvent bien servir toutes ces couleurs puisque, par défaut, seules 16 sont utilisables dans la totalité des applications ? En fait, il faut ruser et parfois modifier les sources des logiciels que vous utilisez couramment. Le plus difficile étant de faire comprendre à une application utilisant les bibliothèques ncurses qu'il faut dépasser les limites standard.
Cependant, un certain nombre de manipulations sont très faciles à faire pour améliorer l'aspect de certains logiciels.
Si nous prenons le cas le plus facile, nous avons l'invite du shell. Notre exemple portera ici sur zsh mais pourra être appliqué à d'autres shells sans problème. Nous allons composer une variable d'environnement RPS1. Celle-ci permet de définir l'invite apparaissant à la droite de la ligne de commande. Il est plus efficace d'utiliser nos nouvelles capacités de colorisation sur cet élément de l'invite.
En effet, si nous désirons, par exemple, créer un dégradé de gris à la fin duquel apparaîtra l'heure, ce dégradé sera composé de caractères espace utilisant chacun une couleur de fond différente. Ce dégradé et donc bel et bien composé de caractères, ce qui implique que nous allons avoir 24 espaces avant l'affichage de l'heure. Si nous appliquons cela à l'invite de gauche (PS1), nous allons inutilement consommer de l'espace sur la ligne de commande. Or, RPS1 sous zsh a la particularité de disparaître dès que le curseur pénètre dans la zone. Notre bel effet ne gênera donc pas la saisie ou l'efficacité du shell.
Voici le contenu de notre variable RPS1 :
export RPS1=$'%e[48;5;233m% %e[48;5;234m% %e[48;5;235m% %e[48;5;236m% %e[48;5;237m% %par e[48;5;238m% %e[48;5;239m% %e[48;5;240m% %e[48;5;241m% %e[48;5;242m% %e[48;5;243m% %e[48;5;244m% %e[48;5;245m% %e[48;5;246m% %e[48;5;247m% %e[48;5;248m% %e[48;5;249m% %e[48;5;250m% %e[48;5;251m% %e[48;5;252m% %e[38;5;232m%%D%H:%M %e[0m%'
Ouch !
Certes, c'est long et un tantinet goret. Nous utilisons les séquences d'échappement que nous venons d'apprendre pour composer la couleur de chacun des 24 espaces (%e[48;5;235m%) avant de placer les variables contenant l'heure (%D%H:%M).
Nous n'oublions pas en fin de chaîne de rendre les paramètres initiaux (%e[0m%). Notez que l'utilisation des paires % est propre à zsh tout comme la syntaxe des variables pour l'heure.
Il existe un moyen permettant d'utiliser ces nouvelles couleurs dans PS1 et ce, de manière efficace. Le problème qui se pose à nous est la difficulté de changement de la couleur d'arrière-plan pour les variables à notre disposition. Si nous prenons, par exemple (avec zsh) la variable %w qui affiche le répertoire courant, nous constatons que sa taille est variable et, de toutes façons, une couleur d'arrière-plan ne s'appliquera qu'à la variable %w. Si nous voulons voir un dégradé de couleurs ou de gris à l'arrière du contenu de %w, nous devons utiliser un script. Celui-ci va alors prendre le contenu de %w et, en fonction du nombre de caractères s'y trouvant, composer une nouvelle variable en utilisant les séquences d'échappement. Bien sûr, cela fonctionnera mais n'oubliez pas, dans ce cas, que le script (ou la fonction zsh) sera appelée à chaque affichage de l'invite. Par conséquent, vous devrez faire face à une baisse de performance.
Curses
N'importe quel script Perl ou autre, ou toute application compilée faisant usage des séquences d'échappement ANSI, pourrait être modifié rapidement et sans le moindre problème. Une autre solution consiste même (en fonction de l'application) à créer un fichier de message NLS (support gettext) en y incluant ces séquences. De cette manière, vous pourrez ajouter de la couleur à un utilitaire sans avoir à recompiler la chose.
Il n'en va pas de même pour des applications en mode console utilisant la bibliothèque de fonctions ncurses (ou curses). Cette dernière permet de simplifier la gestion de l'écran en fournissant un jeu de fonctions de plus haut niveau. Ainsi, bon nombre d'applications comme mutt, top, mc ou vim (pour ne citer qu'elles) utilisent cette bibliothèque. Il est dès lors hors de question d'utiliser des séquences d'échappement. Pour vous en convaincre, vous pouvez faire le test suivant :
- Activez la gestion des couleurs dans la commande ls (si ce n'est déjà fait).
- Placez-vous dans un répertoire où sont placés des fichiers dont le nom sera colorisé par ls.
- Utilisez la commande watch faisant usage d'ncurses :
$ watch -n 1 ls --color
watch est un répétiteur de commandes bien utile dans certains cas. Il permet de lancer à intervalle régulier (ici une seconde) une commande et en afficher la sortie. Le problème avec l'option --color est que nous demandons l'utilisation des séquences ANSI, mais l'application watch ne sait pas les interpréter. Il en résulte un horrible affichage où les séquences sont affichées et non interprétées. Ceci nous prouve qu'ncurses ne fait pas bon ménage avec les séquences ANSI.
Ce problème vient du fait qu'ncurses possède sa propre gestion des couleurs. Les fonctions ncurses tirent les informations utiles de la base terminfo renseignant les applications sur les caractéristiques des terminaux. Ainsi, il ne vous servira à rien de tenter la modification d'applications ncurses si vous ne possédez pas d'entrée xterm en 256 couleurs dans la base terminfo.
Pour vérifier ce point, listez les fichiers présents dans le répertoire /usr/lib/terminfo/x. Ici, vous trouverez normalement toutes les entrées disponibles pour les différentes versions d'xterm. Dans un premier temps, vérifiez si vous ne possédez pas une entrée xterm-color256, xterm-256 ou encore xterm-256color. Vous pourrez ensuite, à l'aide de la commande infocmp, vérifier les paramètres du terminal :
$ infocmp xterm-256color
xterm-256color|xterm with 256 colors,
am, bce, ccc, km, mc5i, mir, msgr, npc, xenl,
colors#256, cols#80, it#8, lines#24, ncv#32, pairs#256,
acsc=``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz||~~,
[...]
La première ligne définit le nom du terminal, suivi par d'éventuels alias puis une description de l'entrée. Nous pouvons d'ores et déjà constater que cette entrée correspond bien à un xterm en 256 couleurs. Dans le doute (on est jamais trop prudent), la troisième ligne comprend le paramètre qui nous intéresse : colors#256. Cette entrée est bien définie pour une gestion des 256 couleurs. Il ne nous reste plus qu'à changer la variable d'environnement adéquate :
$ export TERM=xterm-256color
Et voilà, nous sommes prêt à utiliser une application ncurses en 256 couleurs.
Je parlais tout à l'heure de modifications du code des application utilisant ncurses. Il est en effet très peu probable que vous trouviez une application qui utilise les 256 couleurs de votre nouveau terminal X. Vous serez donc dans l'obligation de modifier les sources des programmes que vous désirez adapter. Pour cela, vous devez comprendre le fonctionnement de la gestion des couleur avec ncurses.
ncurses utilise des paires de couleurs pour afficher les différents éléments qu'il met à la disposition du programmeur. Ces paires sont formées d'une couleur d'avant-plan et d'arrière-plan. Un certain nombre de paires sont déjà définies et vous serez obligé d'en ajouter pour composer vos éléments de couleurs.
La bibliothèques ncurses définit huit couleurs de base lors de son initialisation (noir, rouge, vert, jaune, bleu, magenta, cyan et blanc). Sont initialisées deux autres variables globales :
- COLORS qui renseigne sur le nombre maximum de couleur disponibles ;
- COLOR_PAIR qui renseigne sur le nombre de paires de couleurs.
La fonction init_pair vous permettra ainsi de définir de nouvelles paires de couleur avant/arrière plan :
init_pair(short pair, short f, short b);
Les arguments sont respectivement le numéro de la paire, la couleur d'avant-plan et la couleur d'arrière-plan. Naturellement, le numéro de la paire à initialiser doit être compris entre 1 et COLOR_PAIRS-1. De la même manière, les deux valeurs numériques pour les couleurs doivent être comprises entre 1 et COLORS-1. Ces valeurs sont les mêmes que celles que vous avez utilisé en troisième position dans la commande echo plus haut dans l'article.
Dès que vous aurez défini une ou plusieurs nouvelle(s) paire(s) de couleur, vous pourrez les utiliser avec la fonction attrset couplée à la macro COLOR_PAIR :
attrset(COLOR_PAIR(n));
où n est le numéro de la paire à utiliser. Dès ce moment, tout l'affichage géré par les fonctions de la bibliothèque ncurses (comme mvaddstr, printw ou encore mvprintw) utilisera les nouvelles couleurs de la paire.
Ces quelques indications vous permettront d'apporter de légères modifications aux applications utilisant ncurses. Cependant, en cas de modification plus profonde, comme l'utilisation de plusieurs couleurs dans une barre de menu, ce sera plus difficile à mettre en
uvre. Vous serez sans doute obligé de modifier à la fois l'application, mais également la bibliothèque ncurses en ajoutant de nouveaux widgets. Pour l'heure, il ne semble qu'aucun projet n'existe permettant de développer une gestion avancée des couleurs dans ncurses. La page officielle GNU concernant ncurses précise même "Support for 16-color terminals, such as aixterm and XFree86 xterm". Il semble donc que la gestion de 256 couleurs ne soit pas même volontaire :)
Finissons cet article en précisant qu'un support 256 couleurs dans xterm (ou tout autre terminal) ouvre la porte à un grand nombre de possibilités. Imaginez simplement des applications capables d'utiliser des thèmes (avec de multiples couleurs, des dégradés, des effets de relief poussés et même des pseudo-textures), le tout en monde texte. Il s'agit là d'une bonne voie pour trouver l'équilibre parfait entre beauté et performance.
Liens :
L'astuce de Randy Hron
http://archive.linuxfromscratch.org/mail-archives/lfsapps/2001/07/0216.html
Xterm :
http://dickey.his.com/xterm/
Ncurses :
http://www.gnu.org/software/ncurses/ncurses.html
Copyright (c) Linux Magazine France
Permission vous est donnée de distribuer des copies exactes de cette page tant que cette note de permission et le copyright apparaissent clairement.