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

2024.11.09 : la haute instensité semble être remplacée par du jaune.

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[#£

\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 :

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)