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 effacer la console, par exemple:

echo -e "\x1b[2J"

ou

echo -e "\e[2J"

La documentation en Unix:

$ 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). On peut passer des instructions en ligne de commande avec prompt $e[2J (par exemple).

La séquence générale est ESC[#£

\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 souligné doit être remplacé par:

0 réinitialisation: blanc sur fond noir
1 haute intensité
3n couleur du caractère
4n couleur du fond
5 clignotement
7 inverse-video

3n: Caractère  4n: Fond
30 Gris moyen  40 Noir
31 Rouge       41 Rouge foncé
32 Vert        42 Vert foncé
33 Jaune       43 brun
34 Bleu        44 Bleu foncé
35 Magenta     45 Mauve
36 Cyan        46 Cyan foncé
37 Blanc       47 gris clair
39 Blanc gras

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,"Chaine")

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).

"""python3 ecma.py module - 2007.02.07 - www.jchr.be - GPL2 - v2.1: 2021.12.23
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'
"""
# from __future__ import print_function # uncomment only for python2

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("\x1b[%s;%sm%s" %(fgcolor(fg),bgcolor(bg),txt))

def at(line, column):
  """Add at location line-column ; prints without linefeed"""
  print("\x1b[%s;%sH" %(line, column), end="", flush=True)

def bg(clr, txt):
  """Background color definition"""
  print("\x1b[%sm%s" %(bgcolor(clr),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=="red" or bg=="darkred": return 41
    if bg=="green" or bg=="darkgreen": return 42
    if bg=="brown" or "yellow": return 43
    if bg=="blue" or bg=="marine": return 44
    if bg=="magenta" or bg=="purple": return 45
    if bg=="cyan" or bg=="darkcyan": return 46
    if bg=="white" or bg=="lightgrey" or bg=="lightgray": return 47

def blink():
  """Blinking mode, normal() cancels"""
  print("\x1b[5m", end="")

def clear():
  """Clears the screen"""
  print("\x1b[2J")

def cls():
  """Also clears the screen"""
  print("\x1b[2J")

def fg(clr, txt):
  """Print a text with a foreground color definition"""
  print("\x1b[%sm%s" %(fgcolor(clr),txt))

def fgcolor(fg):
  """Used by several functions: returns a foreground color"""
  try:
    if fg <10: fg +=30
    return fg
  except: # if not a color, hoping a string:
    bg =bg.lower()
    if fg=="grey" or fg=="gray": return 30
    if fg=="red": return 31
    if fg=="green": return 32
    if fg=="yellow": return 33
    if fg=="blue": return 34
    if fg=="magenta": return 35
    if fg=="cyan": return 36
    if fg=="white": return 37
    if fg=="bright": return 39

def home(txt):
  """Writes a chain at the 'home' position (upper left corner)"""
  print("\x1b[H%s" %txt)

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%s" %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[%s;%sm%s" %(fgcolor(fg), bgcolor(bg), txt))

def paintfore(fg, txt):
  """Writes a text, choosing a colour - calls bg()"""
  print("\x1b[%sm%s" %(fgcolor(fg), txt))

def paintback(bg, txt):
  """Writes a text, choosing a background - calls bg()"""
  print("\x1b[%sm%s" %(bgcolor(bg), txt))

def printat(line,column,txt):
  """Writes a chain at a precise line/column"""
  print("\x1b[%s;%sH%s" %(line, column, txt))

Lorsque le fichier est importé, il est possible d'interroger l'aide:

>>> help(ecma)
>>> help(ecma.all)