Helper ANSI


1Présentation

Helper servant à mettre en forme les textes écrits sur la sortie standard en mode console.


2Fonctions de formatage

L'objet \Temma\Utils\Ansi offre plusieurs méthodes statiques. Ces méthodes ajoutent des marqueurs interprétés par les terminaux compatibles ANSI, afin de modifier la manière dont le texte apparaît.

Quelques exemples :

use \Temma\Utils\Ansi as TµAnsi;

// pour écrire du texte en gras (plus épais que le style normal)
print(TµAnsi::bold("bla bla bla"));

// pour écrire du texte "mince" (moins épais que le style normal)
print(TµAnsi::faint("bla bla bla"));

// pour écrire du texte en italique
print(TµAnsi::italic("bla bla bla"));

// pour écrire du texte souligné
print(TµAnsi::underline("bla bla bla"));

// pour écrire du texte qui clignote
print(TµAnsi::blink("bla bla bla"));

// pour écrire du texte en inversion vidéo
print(TµAnsi::negative("bla bla bla"));

// pour écrire du texte barré
print(TµAnsi::strikeout("bla bla bla"));

// pour écrire du texte en rouge
print(TµAnsi::color('red', "bla bla bla"));

// pour écrire du texte en rouge sur un fond bleu
print(TµAnsi::backColor('blue', 'red', "bla bla bla"));

// pour écrire un lien hypertexte
print(TµAnsi::link('https://www.temma.net', 'Site Temma'));

3Couleurs

Les couleurs peuvent être définies par une chaîne de caractères ou par une valeur numérique.

Les chaînes (entre parenthèses la valeur numérique correspondante) :

  • default : Valeur par défaut définie par le terminal.
  • light-black (0)
  • red (1)
  • dark-green (2)
  • olive (3)
  • blue (4)
  • purple (5)
  • teal (6)
  • silver (7)
  • gray (8)
  • light-red (9)
  • green (10)
  • yellow (11)
  • light-blue (12)
  • magenta (13)
  • cyan (14)
  • white (15)
  • black (16)

Les valeurs numériques commencent par les 17 valeurs listées ci-dessus, et finissent par 24 niveaux de gris :


4Blocs

Il est possible de créer facilement des boîtes affichant des titres, avec quatre niveaux différents.

Exemple :

use \Temma\Utils\Ansi as TµAnsi;

print(TµAnsi::title1("Titre niveau 1"));
print(TµAnsi::title2("Titre niveau 2"));
print(TµAnsi::title3("Titre niveau 3"));
print(TµAnsi::title4("Titre niveau 4"));

Résultat :

Il est aussi possible d'insérer des blocs de texte spécifiques :

  • code : Texte en vert sur fond noir.
  • pre : Texte en noir sur fond gris.
  • comment : Texte en italique, en noir sur fond bleu.
  • success : Texte en noir sur fond vert.
  • info : Texte en noir sur fond jaune.
  • alert : Texte en blanc sur fond rouge.

Exemple :

use \Temma\Utils\Ansi as TµAnsi;

print(TµAnsi::block('code', "Bloc de code."));
print(TµAnsi::block('pre', "Bloc de texte brut."));
print(TµAnsi::block('comment', "Commentaire."));
print(TµAnsi::block('success', "Message de réussite."));
print(TµAnsi::block('info', "Message d'information."));
print(TµAnsi::block('alert', "Message d'alerte."));

Résultat :


5Flux XML

La méthode style() permet de formater un flux XML contenant des balises semblables à des balises HTML.


5.1Balises inlines

La manière la plus simple est d'utiliser des balises pour modifier directement le texte :

use \Temma\Utils\Ansi as TµAnsi;

print(TµAnsi::style("<i>italique</i> <u>souligné</u> <b>gras</b><br />
<s>barré</s> <tt>inversé</tt>"));

Résultat :

Les balises existantes sont :

  • <b> : gras
  • <u> : souligné
  • <i> : italique
  • <s> : barré
  • <tt> : vidéo inversée
  • <br /> : insertion d'un retour à la ligne
  • <c> : pour définir la couleur (attribut t pour définir la couleur du texte, attribut b pour définir la couleur de fond)
  • a : pour créer un lien hypertexte (attribut href pour définir l'URL du lien)

5.2Balises blocs

Il est aussi possible d'utiliser des balises représentant les blocs correspondants :

use \Temma\Utils\Ansi as TµAnsi;

$s = <<<EOF
<h1>Titre niveau 1</h1>
<h2>Titre niveau 2</h2>
<h3>Titre niveau 3</h3>
<h4>Titre niveau 4</h4>
<code>Bloc de code.</code>
<pre>Bloc de texte brut.</pre>
<comment>Commentaire.</comment>
<success>Message de réussite.</success>
<info>Message d'information.</info>
<alert>Message d'alerte.</alert>
EOF;
print(TµAnsi::style($s));

Résultat :

Attention, les balises "inline" (<b>, <i>, <u>, <s>, <tt>, <blink>, <color>, <a>) ne peuvent pas être utilisées à l'intérieur d'un bloc.

5.3Gestion des retours chariots

À l'intérieur des blocs, les retours chariots sont préservés.

Par contre, à l'extérieur des blocs, les retours chariots ne sont pas interprétés. Si vous souhaitez insérer un saut de ligne, vous devez utiliser la balise <br />.


5.4Personnalisation

Chaque balise XML peut recevoir des attributs qui permettent de modifier le style du bloc :

  • label : Texte de l'étiquette qui est ajoutée au-dessus du bloc.
  • labelColor : Couleur de fond du label.
  • backColor : Couleur de fond.
  • textColor : Couleur du texte.
  • borderColor : Couleur de bordure.
  • bold : Mettre la valeur true pour que le texte soit en gras.
  • italic : true pour que le texte soit en italique.
  • underline : true pour que le texte soit souligné.
  • faint : true pour que le texte apparaisse avec une intensité moindre.
  • strikeout : true pour que le texte soit barré.
  • blink : true pour que le texte clignote.
  • reverse : true pour que le texte apparaisse en inversion vidéo.
  • line : Chaîne de caractères contenant les sumboles à utiliser pour composer la bordure. C'est une chaîne de 8 caractères : le coin supérieur gauche, la ligne horizontale supérieure, le coin supérieur droit, la ligne verticale droite, le coin inférieur droit, la ligne horizontale inférieure, le coin inférieur gauche, la ligne verticale gauche.
  • padding : Taille de la marge inférieure (nombre de lignes vides au-dessus et en dessous du texte, à l'intérieur du bloc).
  • marginTop : Taille de la marge extérieure supérieure (nombre de lignes vides au-dessus du bloc).
  • marginBottom : Taille de la marge extérieure inférieure (nombre de lignes vides en dessous du bloc).

Exemple :

use \Temma\Utils\Ansi as TµAnsi;

// bloc <code> avec un fond gris,
// une étiquette au-dessus, et une
// marge inférieure de 5 lignes
print(TµAnsi::style("<code backColor='gray' label='Titre'
 marginBottom='5'>Code stylisé.</code>"));

Résultat :


6Création et modification de styles

Il est possible de modifier le style d'un bloc, en changeant sa couleur de fond, la couleur du texte, la couleur de la bordure, les caractères utilisés pour dessiner la bordure, sa marge intérieure et extérieure.

La méthode setStyle() prend en paramètre le nom du bloc à modifier. Si aucun bloc n'existe avec ce nom, il est créé. Tous les autres paramètres sont optionnels, et servent à définir une caractéristique du bloc.

Signature de la méthode :

setStyle(
    string $tag,
    ?string $display=null,
    null|int|string $backColor=null,
    null|int|string $textColor=null,
    null|int|string $borderColor=null,
    ?string $labelColor=null,
    ?bool $bold=null,
    ?bool $italic=null,
    ?bool $underline=null,
    ?bool $faint=null,
    ?bool $strikeout=null,
    ?bool $blink=null,
    ?bool $reverse=null,
    ?string $label=null,
    ?string $line=null,
    ?int $padding=null,
    ?int $marginiTop=null,
    ?int $marginBottom=null
) : array

Paramètres :

  • $tag : Nom du style à modifier ou à créer.
  • $display : Mettre la valeur 'block' pour créer un nouveau bloc.
  • $backColor : Couleur de fond.
  • $textColor : Couleur du texte.
  • $borderColor : Couleur de bordure.
  • $labelColor : Couleur de fond du label (voir plus bas).
  • $bold : Mettre la valeur true pour que le texte soit en gras.
  • $italic : true pour que le texte soit en italique.
  • $underline : true pour que le texte soit souligné.
  • $faint : true pour que le texte apparaisse avec une intensité moindre.
  • $strikeout : true pour que le texte soit barré.
  • $blink : true pour que le texte clignote.
  • $reverse : true pour que le texte apparaisse en inversion vidéo.
  • $line : Chaîne de caractères contenant les symboles à utiliser pour composer la bordure. C'est une chaîne de 8 caractères : le coin supérieur gauche, la ligne horizontale supérieure, le coin supérieur droit, la ligne verticale droite, le coin inférieur droit, la ligne horizontale inférieure, le coin inférieur gauche, la ligne verticale gauche.
  • $padding : Taille de la marge inférieure (nombre de lignes vides au-dessus et en dessous du texte, à l'intérieur du bloc).
  • $marginTop : Taille de la marge extérieure supérieure (nombre de lignes vides au-dessus du bloc).
  • $marginBottom : Taille de la marge extérieure inférieure (nombre de lignes vides en dessous du bloc).

Valeur de retour : Tableau associatif contenant l'ancienne définition du style (tableau vide si le style n'existait pas).

Exemple :

use \Temma\Utils\Ansi as TµAnsi;

// création du style "eighties"
TµAnsi::setStyle(
    tag: 'eighties',
    display: 'block',
    backColor: 'cyan',
    textColor: 'magenta',
    borderColor: 'white',
    bold: true,
    line: '+-+|+-+|',
    padding: 1,
    marginBottom: 1,
);
// utilisation du bloc
print(TµAnsi::block('eighties', "Texte spécial"));

// modification du style (suppression du gras, définition de la couleur de label)
TµAnsi::setStyle('eighties', bold: false, labelColor: 'red');

// utilisation du style en ajoutant un label
print(TµAnsi::style("<eighties label='Label du bloc'>Autre texte</eighties>"));

Résultat :


7Indicateur d'activité

Lorsqu'un script doit effectuer des traitements longs, il peut être utile de fournir à l'utilisateur une indication visuelle lui indiquant que le programme est toujours en cours d'exécution.

use \Temma\Utils\Ansi as TµAnsi;

// démarrage de l'indicateur d'activité
TµAnsi::throbberStart("Traitement en cours...");

// traitements
while (condition) {
    // traitement...

    // on fait tourner les symboles
    TµAnsi::throbberGo();
}
// fin du traitement
TµAnsi::throbberEnd("Traitement terminé");

Résultat :

Vous pouvez modifier l'animation, en fournissant une chaîne de caractère ou un tableau, contenant les éléments de l'animation.

use \Temma\Utils\Ansi as TµAnsi;

TµAnsi::throbberStart("Traitement en cours...", "/−\\|");
while (condition) {
    // traitement...
    TµAnsi::throbberGo();
}
TµAnsi::throbberEnd("Traitement terminé");

Résultat :


8Barre de progression

Pour certains types de traitements, il est préférable d'indiquer à l'utilisateur l'état d'avancement jusqu'à sa complétion. Dans ce cas, une barre de progression permet de matérialiser graphiquement cet avancement.

use \Temma\Utils\Ansi as TµAnsi;

// démarrage de la barre de progression
TµAnsi::progressStart("Traitement en cours...");

// traitements
while (condition) {
    // traitement...

    // on fait avancer la barre
    TµAnsi::progressGo();
}
// fin du traitement
TµAnsi::progressEnd("Traitement terminé");

Résultat :

La méthode statique progressStart() peut prendre deux paramètres (optionnels) :

  • $text (string) : Texte par défaut à afficher au-dessus de la barre de progression. (valeur par défaut&nbp;: chaîne vide)
  • $units (int) : Nombre d'unités représentant la complétion totale. (valeur par défaut : 100)

La méthode statique progressGo() peut prendre deux paramètres (optionnels) :

  • $units (int) : Nombre d'unités d'avancement. Peut prendre une valeur négative. (valeur par défaut : 1)
  • $text (string) : Texte à afficher au-dessus de la barre de progression. (valeur par défaut : chaîne vide, pour utiliser la valeur définie lors de l'appel à progressStart())

Il existe aussi une méthode statique progressSet(), qui permet de définir directement la valeur de progression (et non pas l'incrément de progression, comme le fait la méthode progressGo()). Elle prend en premier paramètre la valeur d'avancement, et en second paramètre (optionnel) le texte à afficher.

Il est possible de modifier l'affichage de la barre de progression avec la méthode statique setProgressStyle(), qui peut prendre cinq paramètres (tous optionnels) :

  • $backColor (string) : couleur de la barre de progression non complétée.
  • $frontColor (string) : couleur de la barre de progression complétée.
  • $percentage (bool) : true pour afficher un pourcentage de complétion, false pour afficher le nombre d'unités complétées et le nombre total. (valeur par défaut : true)
  • $width (int) : Diviseur de la largeur d'écran. Par exemple, si la valeur est 3, la barre de progression occupera un tiers de la largeur d'écran. (valeur par défaut : 1, pour occuper toute la largeur de l'écran)
  • $bold (string) : false pour que le texte ne soit pas en gras.
use \Temma\Utils\Ansi as TµAnsi;

// couleur : jaune sur fond bleu
// affichage en unités (pas en pourcentage) sur une moitié d'écran
TµAnsi::setProgressStyle(
    backColor: 'blue',
    frontColor: 'yellow',
    percentage: false,
    width: 2,
    bold: false
);

// affichage sur 120 unités
TµAnsi::progressStart("Traitement en cours...", 120);

while (condition) {
    // traitement...
    TµAnsi::progressGo();
}
TµAnsi::progressEnd("Traitement terminé");

Résultat :


9Méthodes utilitaires

L'objet \Temma\Utils\Ansi propose aussi deux fonctions statiques qui peuvent être utilisées pour faire des manipulations de chaînes de caractères contenant des caractères de contrôle ANSI.


9.1strlen()

Cette méthode statique retourne le nombre de caractères imprimables dans une chaîne de caractères UTF-8.

Signature de la méthode :

strlen(string $string) : int

Exemple :

use \Temma\Utils\Ansi as TµAnsi;

$s = TµAnsi::bold('hello');
$length = TµAnsi::strlen($s); // 5

9.2wordwrap()

Cette méthode statique effectue le même traitement que la fonction PHP wordwrap(), elle coupe les chaînes de caractères pour que chaque ligne ne fasse pas plus que le nombre de caractères passé en paramètre, en gardant les mots entiers, mais elle ne compte que les caractères imprimables. Elle préserve toutefois les caractères non imprimables comme les séquences de contrôle ANSI.

Signature de la méthode :

wordwrap(string $string, int $width) : string

Paramètres :

  • $string : La chaîne à découper.
  • $width : Nombre de caractères maximal par ligne.

Exemple :

use \Temma\Utils\Ansi as TµAnsi;

$s = TµAnsi::bold('hello') . ' ' . TµAnsi::italic('world');
$s = TµAnsi::wordwrap($s, 8);
// équivalent à :
// $s = TµAnsi::bold('hello') . "\n" . TµAnsi::italic('world');