Séquences ECMA-48 CSI
Voir manuel python Affichage
LES séquences ECMA-48 permettent une spécification (couleur, endroit) de la sortie sur console et commencent par l'octet 27 "ESC". Cela permet notamment d'écrire à un endroit particulier de l'écran, effacer la console ou colorer caractères et fond. Cette fonctionnalité est d'origine avec GNU/Linux.
Pour obtenir la documentation en Unix (q pour en sortir):
$ man console_codes
Sous Windows NT et suivant, il suffirait d'ajouter la ligne DEVICE=ANSI.SYS dans le fichier CONFIG.NT (ça n'a pas marché avec XP).
Les séquences ECMA permettent de passer des instructions en ligne de commande avec des séquences de caractère, sous la formule générale ESC[#£
- ESC est l'octet 27, à coder "\e", "\033" (octal) ou "\x1b" (hexadécimal) ; en python: chr(27)
- [ est la parentèse carrée ouvrante
- # symbolise ici un nombre en base décimale, s'il y a plusieurs paramètres, les séparer par un point-virgule
- £ symbolise une lettre de l'alphabet
\x1b[2J efface tout l'écran
\x1b[H place le curseur en haut à gauche
\x1b[#;#H place le curseur à un point particulier de l'écran. \x1b[1;1H place le curseur en haut à gauche
\x1b[#A déplace le curseur de # caractères vers le haut
\x1b[#B déplace le curseur de # caractères vers le bas
\x1b[#C déplace le curseur de # caractères vers la droite
\x1b[#D déplace le curseur de # caractères vers la gauche
\x1b[#f place le curseur à la ligne # , première colonne
\x1b[#L insère # lignes à la position du curseur, repousse la suite
\x1b[#M efface # lignes à la position du curseur, ramène les suivantes
\x1b[#a place le curseur à la ligne #, colonne inchangée
\x1b[#;#r définit une première et une dernière ligne pour le scroll
\x1b[s sauvegarde la position du curseur
\x1b[u replace le curseur à la position préalablement sauvegardée
\x1b[?25l cache le curseur; \x1b[?25h le rétablit
Les couleurs (très limitées) se codent \x1b[#m, le croisillon doit être remplacé par:
0 réinitialisation: blanc sur fond noir
1 haute intensité
3 italique
4 souligné
5 clignotement
7 inverse-video
Caractère Fond 30 Gris moyen 40 Gris foncé 31 Rouge 41 Rouge foncé 32 Vert 42 Vert foncé 33 Jaune 43 brun 34 Bleu 44 Bleu foncé 35 Mauve 45 Mauve foncé 36 Cyan 46 Cyan foncé 37 Blanc 47 gris clair 39 Blanc gras
Remarques :
- Il est possible de composer ces codes : \033[3;4;5;33;41mTexte donne un texte jaune (33) sur fond rouge (41) italique (3), souligné (4) et clignotant (4)
- Les couleurs sont composées avec rouge =1, vert =2 et bleu =quatre. En synthèse des lumières, jaune vaut rouge + vert (1 +2 =3), magenta vaut rouge + bleu (1 +4 =5), cyan vaut vert + bleu (2 +4 =6) et blanc vaut rouge + vert + bleu (1 +2 +4 =7).
En python
On compose couleurs de caractère et de fond en séparant les nombres par un point virgule:
>>> print("\x1b[1;33;45m"+"Spam?"+"\x1b[0m")
Spam?
Le module ecma permet l'utilisation simple de ces codes:
paintat(ligne,colonne,texte,fond,"Texte")
Voir Modules utilisateurs pour l'utilisation d'un module fait à la maison. Copiez le code ci-dessous dans un fichier nommé ecma.py, que vous placez par exemple dans le répertoire de votre script, ou (avec les droits de super-utilisateur) à l'adresse /usr/lib/python3.7 (ou selon votre version de python).
"""python ecma.py module - www.jchr.be - GPL2 (begun 2007.02.07 py2) v2.1: 2021.12.23 for python3 v2.2: 2024.04.01 using formated strings f"" Enhanced printing console functions using some ECMA-48 sequences: position= line, column ; colors= foreground, background Color composition: add red=1, green=2 or blue=4. You can use number or chain: Foreground: Background: darker than foreground 0, 30 or 'grey' 0, 40 or 'black' 1, 31 or 'red' 1, 41, 'red' or 'darkred' 2, 32 or 'green' 2, 42, 'green' or 'darkgreen' 3, 33 or 'yellow' 3, 43, 'yellow' or 'brown' 4, 34 or 'blue' 4, 44, 'blue' or 'marine' 5, 35 or 'magenta' 5, 45, 'magenta' or 'purple' 6, 36 or 'cyan' 6, 46, 'cyan' or 'darkcyan' 7, 37 or 'white' 7, 47, 'white' or 'lightgrey' 9, 39 or 'bright' """ def add(txt): """Add a text at the last location, with no linefeed""" print(txt, end="", flush=True) def all(line, column, fg, bg, txt): """Prints a text at a precise location with colors - calls at(), fg(), bg()""" at(line,column) print(f"\x1b[{fgcolor(fg)};{bgcolor(bg)}m{txt}") def at(line, column): """Add at location line-column ; prints without linefeed""" print(f"\x1b[{line};{column}H", end="", flush=True) def bg(clr, txt): """Background color definition""" print(f"\x1b[{bgcolor(clr)}m{txt}") def bgcolor(bg): """Used by several functions: returns a background color""" try: if bg<10 : bg+=40 return bg except: # if not a number, hoping a string: bg=bg.lower() if bg =="black" : return 40 if bg in ("red", "darkred") : return 41 if bg in ("green", "darkgreen") : return 42 if bg in ("brown", "yellow") : return 43 if bg in ("blue", "marine") : return 44 if bg in ("magenta", "purple") : return 45 if bg in ("cyan", "darkcyan") : return 46 if bg in ("white", "lightgrey", "lightgray") : return 47 def blink(): """Blinking mode, normal() cancels""" print("\x1b[5m", end="", flush=True) def clear(): """Clears the screen""" print("\x1b[2J", end="", flush=True) def cls(): """Also clears the screen""" print("\x1b[2J", end="", flush=True) def fg(clr, txt): """Print a text with a foreground color definition""" print("\x1b[{fgcolor(clr)}m{,txt}") def fgcolor(fg): """Used by several functions: returns a foreground color number""" if fg.isnumber() : if fg < 10: fg +=30 : if 29 < fg < 40 and fg !=38 : return fg else : print("Not a valid number") fg =str(fg).lower() # if not a color, hoping a string match fg.lower() case "grey" : return 30 case "gray" : return 30 case "red" : return 31 case "green" : return 32 case "yellow" : return 33 case "blue" : return 34 case "magenta" : return 35 case "cyan" : return 36 case "white" : return 37 case "bright" : return 39 case _ : print("Not a valid string") def home(txt): """Writes a chain at the 'home' position (upper left corner)""" print(f"\x1b[H{txt}", end=""; ) def inverse(): """Video inverse, normal() cancels""" print("\x1b[7m", end="") def new(txt): """Clears the screen and writes at the home position - same as clear + printat(1,1,chain)""" print("\x1b[2J\x1b[H{txt}") def normal(): """Normal video and colours, non-blinking mode""" print("\x1b[0m") def paint(fg, bg, txt): """Writes a colored string - calls fg() and bg()""" print("\x1b[{fgcolor(fg)};{bgcolor(bg)}m{txt}") def paintfore(fg, txt): """Writes a text, choosing a colour - calls bg()""" print(f"\x1b[{fgcolor(fg)}m{txt}") def paintback(bg, txt): """Writes a text, choosing a background - calls bg()""" print(f"\x1b[{bgcolor(bg)}m{txt}") def printat(line,column,txt): """Writes a chain at a precise line/column""" print(f"\x1b[{line};{column}H{txt}")
Lorsque le fichier est importé, il est possible d'interroger l'aide:
>>> help(ecma)
>>> help(ecma.all)