$ cd ../dokuwiki/plugins
$ git clone git://github.com/cpjobling/plugin-cli.git cli
Le dossier contiendra :
; style.css
: tous les styles pour cli
; syntax.php
: plugin script
Le plugin est maintenant installé.
Details
" comment="#">
* user@host:~/somedir $ ls \
* > # List directory
* file1 file2
*
* 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
*/
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(']|[(?:])*>\r?\n?(?=.*? )',$mode,'plugin_cli');
/*
* The [)]? and |[(?:] is to work around a bug in lexer.php
* wrt nested (...)
*/
}
function postConnect() {
$this->Lexer->addExitPattern('\r?\n?','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 .= '';
break;
case DOKU_LEXER_UNMATCHED :
$this->_render_conversation($match, $renderer);
break;
case DOKU_LEXER_EXIT :
$renderer->doc .= "
";
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 .= '' . $renderer->_xmlEntities($promptc[0]) . "";
// 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 .= '' . $renderer->_xmlEntities($commands[0]) . "";
// Render comment if there is one
if ($commands[1]) {
$renderer->doc .= '' .
$renderer->_xmlEntities($this->comment_str . $commands[1]) . "";
}
$renderer->doc .= DOKU_LF;
} else {
// render as output
$renderer->doc .= '' . $renderer->_xmlEntities($line) . "" . DOKU_LF;
$this->prompt_continues=false;
}
} else {
$this->prompt_continues = true;
// format prompt
$prompt = substr($line, 0, $index) . $this->prompt_str;
$renderer->doc .= '' . $renderer->_xmlEntities($prompt) . "";
// 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 .= '' . $renderer->_xmlEntities($commands[0]) . "";
// Render comment if there is one
if ($commands[1]) {
$renderer->doc .= '' .
$renderer->_xmlEntities($this->comment_str . $commands[1]) . "";
}
$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 */
===== Configuration =====
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.
===== Utilisation =====
==== Syntaxe ====
Une interaction Bash simple :
user@host:~/somedir $ ls # List current directory
conf lang README screen.gif ui
info.txt manager.dat renderer.php syntax.php
user@host:~/somedir $
s'affiche ainsi :
transcript
s'affiche :
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 $
Résultat :
user@host:~/somedir $ ls # List current directory
conf lang README screen,gif ui
info.txt manager.dat renderer.php syntax.php
user@host:~/somedir $
=== Script shell root avec commentaires ===
Texte : (caractère de commentaire shell par défaut):
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 #
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 #
user@host:~/somedir $ ls \
> # List directory
file1 file2
user@host:~/somedir $ ls # List current directory
conf lang README screen,gif ui
info.txt manager.dat renderer.php syntax.php
user@host:~/somedir $
=== Fenêtre de commande Windows ===
Texte :
C:\Users\User>REM hello world!
C:\Users\User>echo 'hello world!'
'hello world!'
Résultat :
irb(main):001:0> 2+2
=> 4
irb(main):002:0>
=== Python ===
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
>>>
=== Python + Windows Shell (Nested CLIs) ===
Texte :
C:\Users\Chris Jobling>python
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
C:\Users\Chris Jobling>
Résultat :
# rpm -ivh darcs-1.0.9-3.fc6.i386.rpm
Preparing... ########################################### [100%]
1:darcs ########################################### [100%]