Ce plugin formate la sortie d'une ligne de commande, par exemple pour un manuel d'utilisation ou un tutoriel en ligne. Il est conçu pour fonctionner avec la sortie d'un shell Unix standard, mais devrait convenir pour documenter d'autres types d'interaction CLI, par ex. Fenêtre de commande Windows, Python et Ruby, Matlab, etc.
Sa conception permet d'afficher une transcription CLI (par exemple, une copie de texte à partir d'une fenêtre de console) avec un minimum de balisage supplémentaire.
On peut ajuster le style de l'affichage à l'aide d'une feuille de style. Pour plus de détails, reportez-vous à style.css.
On suppose que :
Avec PHP 7
Pour les plugins qui donnent des erreurs, éditez le fichier lib/plugins/<plugin>/syntax.php pour le modifier comme ceci :
comme indiqué dans les messages d'erreur
Le code source de ce plugin est hébergé chez GitHub à https://github.com/cpjobling/plugin-cli.
Pour installer le plugin lorsque git est installé sur votre serveur DokuWiki, il vous suffit de lancer depuis votre serveur :
$ cd ../dokuwiki/plugins $ git clone git://github.com/cpjobling/plugin-cli.git cli
Le dossier contiendra :
Le plugin est maintenant installé.
Details
<?php /** * Command Line Interface (CLI) Plugin * Typeset transcripts of interactive sessions with mimumum effort. * Syntax: * <cli prompt="$ " continue="> " comment="#"> * user@host:~/somedir $ ls \ * > # List directory * file1 file2 * </cli> * prompt --- [optional] prompt character used. '$ ' is default - note the space. * comment --- [optional] comment character used. '#' is default - note no space. * continue --- [optional] regex of shell continuation '/^> /' is the default. * The defaults above match Bourne shell ${PS1} and ${PS2} prompts and comment * * Acknowledgements: * Borrows heavily from the boxes plugin! * Support for continuation added by Andy Webber * Improved parsing added by Stephane Chazelas * * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author Chris P. Jobling <C.P.Jobling@Swansea.ac.uk> */ if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/'); if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); require_once(DOKU_PLUGIN.'syntax.php'); /** * All DokuWiki plugins to extend the parser/rendering mechanism * need to inherit from this class */ class syntax_plugin_cli extends DokuWiki_Syntax_Plugin { var $prompt_str = '$ '; var $prompt_cont = '/^> /'; // this is a regex var $prompt_continues = false; var $comment_str = '#'; /** * return some info */ function getInfo(){ return array( 'author' => 'Chris P. Jobling; Stephan Chazelas; Andy Webber', 'email' => 'C.P.Jobling@Swansea.ac.uk', 'date' => '2008-13-02', 'name' => 'Command Line Interface (CLI) Plugin', 'desc' => 'Renders transcripts of command line interactions, e.g. for shell and dynamic language interpretor tutorials', 'url' => 'http://eehope.swan.ac.uk/dokuwiki/plugins:cli', ); } /** * What kind of syntax are we? */ function getType(){ return 'protected'; } /** * What kind of syntax do we allow (optional) */ // function getAllowedTypes() { // return array(); // } // override default accepts() method to allow nesting // - ie, to get the plugin accepts its own entry syntax function accepts($mode) { if ($mode == substr(get_class($this), 7)) return true; return parent::accepts($mode); } /** * What about paragraphs? (optional) */ function getPType(){ return 'block'; } /** * Where to sort in? */ function getSort(){ return 601; } /** * Connect pattern to lexer */ function connectTo($mode) { $this->Lexer->addEntryPattern('<cli(?:[)]?' . '"(?:\\\\.|[^\\\\"])*"' . /* double-quoted string */ '|\'(?:\\\\.|[^\'\\\\])*\'' . /* single-quoted string */ '|\\\\.' . /* escaped character */ '|[^\'"\\\\>]|[(?:])*>\r?\n?(?=.*?</cli>)',$mode,'plugin_cli'); /* * The [)]? and |[(?:] is to work around a bug in lexer.php * wrt nested (...) */ } function postConnect() { $this->Lexer->addExitPattern('\r?\n?</cli>','plugin_cli'); } /** * Handle the match */ function handle($match, $state, $pos, &$handler){ switch ($state) { case DOKU_LEXER_ENTER : $args = substr($match, 4, -1); return array($state, $args); case DOKU_LEXER_MATCHED : break; case DOKU_LEXER_UNMATCHED : return array($state, $match); case DOKU_LEXER_EXIT : return array($state, ''); case DOKU_LEXER_SPECIAL : break; } return array(); } /** * Create output */ function render($mode, &$renderer, $data) { if($mode == 'xhtml'){ list($state, $match) = $data; switch ($state) { case DOKU_LEXER_ENTER : $args = $match; $this->_process_args($args); $renderer->doc .= '<pre class="cli">'; break; case DOKU_LEXER_UNMATCHED : $this->_render_conversation($match, $renderer); break; case DOKU_LEXER_EXIT : $renderer->doc .= "</pre>"; break; } return true; } return false; } function _extract($args, $param) { /* * extracts value from $args for $param * xxx = "foo\"bar" -> foo"bar * xxx = a\ b -> a b * xxx = 'a\' b' -> a' b * * returns null if value is empty. */ if (preg_match("/$param" . '\s*=\s*(' . '"(?:\\\\.|[^\\\\"])*"' . /* double-quoted string */ '|\'(?:\\\\.|[^\'\\\\])*\'' . /* single-quoted string */ '|(?:\\\\.|[^\\\\\s])*' . /* escaped characters */ ')/', $args, $matches)) { switch (substr($matches[1], 0, 1)) { case "'": $result = substr($matches[1], 1, -1); $result = preg_replace('/\\\\([\'\\\\])/', '$1', $result); break; case '"': $result = substr($matches[1], 1, -1); $result = preg_replace('/\\\\(["\\\\])/', '$1', $result); break; default: $result = preg_replace('/\\\\(.)/', '$1', $matches[1]); } if ($result != "") return $result; } } function _process_args($args) { // process args to CLI tag: sets $comment_str and $prompt_str if (!is_null($prompt = $this->_extract($args, 'prompt'))) $this->prompt_str = $prompt; if (!is_null($comment = $this->_extract($args, 'comment'))) $this->comment_str = $comment; } function _render_conversation($match, &$renderer) { $prompt_continues = false; $lines = preg_split('/\n\r|\n|\r/',$match); if ( trim($lines[0]) == "" ) unset( $lines[0] ); if ( trim($lines[count($lines)]) == "" ) unset( $lines[count($lines)] ); foreach ($lines as $line) { $index = strpos($line, $this->prompt_str); if ($index === false) { if ($this->prompt_continues) { if (preg_match($this->prompt_cont, $line, $promptc) === 0) $this->prompt_continues = false; } if ($this->prompt_continues) { // format prompt $renderer->doc .= '<span class="cli_prompt">' . $renderer->_xmlEntities($promptc[0]) . "</span>"; // Split line into command + optional comment (only end-of-line comments supported) $command = preg_split($this->prompt_cont, $line); $commands = explode($this->comment_str, $command[1]); // Render command $renderer->doc .= '<span class="cli_command">' . $renderer->_xmlEntities($commands[0]) . "</span>"; // Render comment if there is one if ($commands[1]) { $renderer->doc .= '<span class="cli_comment">' . $renderer->_xmlEntities($this->comment_str . $commands[1]) . "</span>"; } $renderer->doc .= DOKU_LF; } else { // render as output $renderer->doc .= '<span class="cli_output">' . $renderer->_xmlEntities($line) . "</span>" . DOKU_LF; $this->prompt_continues=false; } } else { $this->prompt_continues = true; // format prompt $prompt = substr($line, 0, $index) . $this->prompt_str; $renderer->doc .= '<span class="cli_prompt">' . $renderer->_xmlEntities($prompt) . "</span>"; // Split line into command + optional comment (only end-of-line comments supported) $commands = explode($this->comment_str, substr($line, $index + strlen($this->prompt_str))); // Render command $renderer->doc .= '<span class="cli_command">' . $renderer->_xmlEntities($commands[0]) . "</span>"; // Render comment if there is one if ($commands[1]) { $renderer->doc .= '<span class="cli_comment">' . $renderer->_xmlEntities($this->comment_str . $commands[1]) . "</span>"; } $renderer->doc .= DOKU_LF; } } } } //Setup VIM: ex: et ts=4 enc=utf-8 sw=4 : ?>
style.css
These may be modified to suit your own requirements.
/* plugin:cli */ .cli_output { color: blue; } .cli_comment { color: brown; } .cli_prompt { color: green; } .cli_command { color: red; } // nested CLI pre.cli pre.cli { background-color: #F8F8F8; } /* end plugin:cli */
Le plugin n'a pas de paramètres de configuration, bien que vous souhaitiez peut-être revoir le jeu de couleurs par défaut dans style.css pour vous assurer qu'il convient à votre wiki.
Une interaction Bash simple :
<cli> user@host:~/somedir $ ls # List current directory conf lang README screen.gif ui info.txt manager.dat renderer.php syntax.php user@host:~/somedir $ </cli>
s'affiche ainsi :
user@host:~/somedir $ ls # List current directory conf lang README screen.gif ui info.txt manager.dat renderer.php syntax.php user@host:~/somedir $
Syntaxe complète :
<cli prompt='prompt ' comment='comment'> transcript </cli>
s'affiche :
transcript
Le <cli … > du début doit apparaître sur une seule ligne. Le contenu de la transcription peut apparaître sur autant de lignes que nécessaire.
Cette page fournit un ensemble de tests pour cli et sert également d'exemple de son utilisation.
Texte :
<cli> user@host:~/somedir $ ls conf lang README screen.gif ui info.txt manager.dat renderer.php syntax.php user@host:~/somedir $ wc info.txt # count words in info.txt 55 108 1032 info.txt user@host:~/somedir $ </cli>
Résultat :
user@host:~/somedir $ ls conf lang README screen.gif ui info.txt manager.dat renderer.php syntax.php user@host:~/somedir $ wc info.txt # count words in info.txt 55 108 1032 info.txt user@host:~/somedir $
Texte :
<cli comment="#"> user@host:~/somedir $ ls # List current directory conf lang README screen,gif ui info.txt manager.dat renderer.php syntax.php user@host:~/somedir $ </cli>
Texte : (caractère de commentaire shell par défaut):
<cli prompt="#"> root@host:~user/somedir # ls # List current directory conf lang README screen,gif ui info.txt manager.dat renderer.php syntax.php root@host:~user/somedir # </cli>
Résultat :
root@host:~user/somedir # ls # List current directory conf lang README screen,gif ui info.txt manager.dat renderer.php syntax.php root@host:~user/somedir #
Ceci est également valable :
<cli prompt="# " comment="#"> root@host:~user/somedir # ls # List current directory conf lang README screen,gif ui info.txt manager.dat renderer.php syntax.php root@host:~user/somedir # </cli>
root@host:~user/somedir # ls # List current directory conf lang README screen,gif ui info.txt manager.dat renderer.php syntax.php root@host:~user/somedir #
Exemple avec une invite de continuation:
<cli prompt="$ " continue="> " comment="#"> user@host:~/somedir $ ls \ > # List directory file1 file2 </cli>
user@host:~/somedir $ ls \ > # List directory file1 file2
<cli prompt="$" comment="#"> user@host:~/somedir $ ls # List current directory conf lang README screen,gif ui info.txt manager.dat renderer.php syntax.php user@host:~/somedir $ </cli>
Texte :
<cli prompt=">" comment="REM"> C:\Users\User>REM hello world! C:\Users\User>echo 'hello world!' 'hello world!' </cli>
Résultat :
C:\Users\User>REM hello world! C:\Users\User>echo 'hello world!' 'hello world!'
Une implémentation simple ne fonctionnera pas pour les résultats car la fin de l'invite est identique au marqueur de résultats !
<cli prompt=">"> irb(main):001:0> 2+2 => 4 irb(main):002:0> </cli>
<cli prompt=">>>"> ActivePython 2.5.1.1 (ActiveState Software Inc.) based on Python 2.5.1 (r251:54863, May 1 2007, 17:47:05) [MSC v.1310 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> 2+2 4 >>> </cli>
Texte :
<cli prompt=">"> C:\Users\Chris Jobling>python <cli prompt=">>>"> ActivePython 2.5.1.1 (ActiveState Software Inc.) based on Python 2.5.1 (r251:54863, May 1 2007, 17:47:05) [MSC v.1310 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> 2+2 4 >>> ^Z </cli> C:\Users\Chris Jobling> </cli>
Résultat :
C:\Users\Chris Jobling>pythonActivePython 2.5.1.1 (ActiveState Software Inc.) based on Python 2.5.1 (r251:54863, May 1 2007, 17:47:05) [MSC v.1310 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> 2+2 4 >>> ^ZC:\Users\Chris Jobling>
<cli prompt="#"> # rpm -ivh darcs-1.0.9-3.fc6.i386.rpm Preparing... ########################################### [100%] 1:darcs ########################################### [100%] </cli>
# rpm -ivh darcs-1.0.9-3.fc6.i386.rpm Preparing... ########################################### [100%] 1:darcs ########################################### [100%]
Pas sûr de pouvoir résoudre ce problème car le marqueur de progression de téléchargement utilise le même caractère que l'invite !
user@host:~/somedir $ ls # List current directory conf lang README screen,gif ui info.txt manager.dat renderer.php syntax.php user@host:~/somedir $ # I intended there to be two blank lines above!