self::LEVEL_DEBUG, "d" => self::LEVEL_DEBUG, "normal" => self::LEVEL_NORMAL, "n" => self::LEVEL_NORMAL, "major" => self::LEVEL_MAJOR, "m" => self::LEVEL_MAJOR, ]; const TYPE_PREFIXES = [ self::LEVEL_MAJOR => [ "section" => [true, "SECTION!", "===", "= ", " =", "==="], "title" => ["TITLE!", null, "T ", "", "---"], "desc" => ["DESC!", "> ", ""], "error" => ["CRITICAL!", "E! ", ""], "warn" => ["ATTENTION!", "W! ", ""], "note" => ["IMPORTANT!", "N! ", ""], "info" => ["IMPORTANT!", "I! ", ""], ], self::LEVEL_NORMAL => [ "section" => [true, "SECTION:", null, ">> ", " <<", "---"], "title" => ["TITLE:", null, "T ", "", null], "desc" => ["DESC:", "> ", ""], "error" => ["ERROR:", "E ", ""], "warn" => ["WARN:", "W ", ""], "note" => ["NOTE:", "N ", ""], "info" => ["INFO:", "I ", ""], ], self::LEVEL_DEBUG => [ "section" => [false, "s", null, ">> ", " <<", null], "title" => ["t", "t ", ""], "desc" => [">", "> ", ""], "error" => ["e", "e ", ""], "warn" => ["w", "w ", ""], "note" => ["i", "i ", ""], "info" => ["D", "D ", ""], ], ]; const RESULT_PREFIXES = [ "step" => ["*", "."], "failure" => ["(FAILURE)", ""], "success" => ["(SUCCESS)", ""], "neutral" => [null, null], ]; function __construct(?array $params=null) { $debug = boolval(cl::get($params, "debug")); $minLevel = cl::get($params, "min_level"); if ($minLevel === null) $minLevel = $debug? self::LEVEL_DEBUG: self::LEVEL_NORMAL; if (!in_array($minLevel, self::VALID_LEVELS)) { $minLevel = cl::get(self::LEVEL_MAP, $minLevel, $minLevel); } if (!in_array($minLevel, self::VALID_LEVELS)) { throw new Exception("$minLevel: invalid level"); } $this->out = new StdOutput(STDOUT); $this->err = new StdOutput(STDERR); $this->minLevel = intval($minLevel); $this->pending = []; $this->inSection = false; $this->titles = null; $this->actions = null; } /** @var StdOutput la sortie standard */ protected $out; /** @var StdOutput la sortie d'erreur */ protected $err; /** @var int level minimum que doivent avoir les messages pour être affichés */ protected $minLevel; /** @var bool est-on dans une section? */ protected $inSection; /** @var array|string section qui est en attente d'affichage */ protected $section; function section($content, int $level=self::LEVEL_NORMAL): void { $this->endSection(); $this->inSection = true; if ($level < $this->minLevel) return; $this->section = $content; } protected function printSection() { if ($this->section !== null) { $this->section = null; } } protected function endSection(): void { $this->inSection = false; $this->section = null; } /** @var array */ protected $titles; /** @var array */ protected $currentTitle; function title($content, int $level=self::LEVEL_NORMAL): void { if ($level < $this->minLevel) return; $this->titles[] = [ "title" => $content, "descs" => [], "print" => true, ]; $this->currentTitle =& $this->titles[count($this->titles) - 1]; } function desc($content, int $level=self::LEVEL_NORMAL): void { if ($level < $this->minLevel) return; $this->currentTitle["descs"][] = $content; } protected function printTitles(): void { $this->printSection(); } protected function endTitle(): void { array_pop($this->titles); if ($this->titles) { $this->currentTitle =& $this->titles[count($this->titles) - 1]; } else { unset($this->currentTitle); } } function print($content, int $level=self::LEVEL_NORMAL): void { if ($level < $this->minLevel) return; $this->printTitles(); $this->out->print($content); } /** @var array */ protected $actions; /** @var array */ protected $currentAction; function action($content, int $level=self::LEVEL_NORMAL): void { $this->actions[] = [ "level" => $level, "contents" => [$content], "result" => null, "print" => true, ]; $this->currentAction =& $this->actions[count($this->actions) - 1]; } function printActions(): void { $this->printTitles(); } function step($content): void { $this->printActions(); } function success($content=null): void { $this->currentAction["contents"][] = $content; $this->currentAction["result"] = true; $this->printActions(); $this->endAction(); } function failure($content=null): void { $this->currentAction["contents"][] = $content; $this->currentAction["result"] = false; $this->printActions(); $this->endAction(); } function neutral($content=null): void { $this->currentAction["contents"][] = $content; $this->currentAction["result"] = null; $this->printActions(); $this->endAction(); } protected function endAction(): void { array_pop($this->actions); if ($this->actions) { $this->currentAction =& $this->actions[count($this->actions) - 1]; } else { unset($this->currentAction); } } function info($content, int $level=self::LEVEL_NORMAL): void { if ($level < $this->minLevel) return; $this->printActions(); } function note($content, int $level=self::LEVEL_NORMAL): void { if ($level < $this->minLevel) return; $this->printActions(); } function warn($content, int $level=self::LEVEL_NORMAL): void { if ($level < $this->minLevel) return; $this->printActions(); } function error($content, int $level=self::LEVEL_NORMAL): void { if ($level < $this->minLevel) return; $this->printActions(); } function end(bool $all=false) { if ($all) { while ($this->actions) $this->neutral(); while ($this->titles) $this->endTitle(); $this->endSection(); } elseif ($this->actions) { $this->endAction(); } elseif ($this->titles) { $this->endTitle(); } else { $this->endSection(); } } }