====== Command Line Interface (CLI) Plugin ======
---- plugin ----
description: Format command line transcripts
author : Chris P. Jobling
email : C.P.Jobling@Swansea.ac.uk
type : syntax
lastupdate : 2010-08-07
compatible :
depends :
conflicts :
similar : code
tags : code, cli, syntax, highlighting
----
This [[wiki:plugins|plugin]] brings a Command Line Interface formatter to [[wiki:Dokuwiki]] allowing you to format the output of a transcript say for a user manual or on-line tutorial. It is designed to work with the output of a standard Unix Bash Shell, but should be suitable to document other kinds of CLI interaction, e.g. Windows Command Window, Python and Ruby, Matlab, etc.
The assumptions made are
- all user commands start with a prompt
- the CLI prompt will end in a recognizable character (typically '$' or '>')
- user commands will follow the CLI prompt on the same line
- lines that do not start with a prompt are outputs from the CLI((this turns out to be a problem for the Ruby interactive shell //irb// which seems to prefix every line with a prompt!))
A key design feature is that it should be possible to display a CLI transcript (e.g. output from a history file or copy of text from a console window) for display with the mimumum of additional markup.
It is possible to adjust the style of the display using a style sheet. For details refer to [[#style.css]].
==== Notes ====
* My version of this page -- which could be more recently updated -- can be found [[http://www.cpjobling.org.uk/dokuwiki/plugins:cli|here]]
* Since 7 August 2010 the source for this plugin code has been hosted at GitHub at http://github.com/cpjobling/plugin-cli. To install the plugin when you have ''git'' installed on your DokuWiki server, you just need to:
cd ../dokuwiki/plugins
git clone git://github.com/cpjobling/plugin-cli.git cli
=====Acknowledgements=====
A similar feature is to be found in [[http://moinmoin.wikiwikiweb.de/|MoinMoin Wiki]] and [[http://www.tiddlywiki.com/|TiddlyWiki]]. The styles are based on those developed for the [[http://www.ee.surrey.ac.uk/Teaching/Unix/|UNIX Tutorial for Beginners]] by Michael Stonebank. The plugin and its documentation are based on lessons learned from the [[http://wiki.splitbrain.org/plugin:tutorial|Plugin Tutorial]] and Christopher Smith's implementation and documentation of the [[http://wiki.splitbrain.org/plugin:boxes|boxes plugin]].
Several improvements suggested by Stephane Chazelas and Andy Webber.
===== Syntax =====
A simple Bash Shell interaction:
user@host:~/somedir $ ls # List current directory conf lang README screen.gif ui info.txt manager.dat renderer.php syntax.php user@host:~/somedir $The full syntax:
" comment="#">
* user@host:~/somedir $ ls \
* > # List directory
* file1 file2
*
'; 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 */
===== Revision History =====
* 2007-09-10 --- First release
* 2008-13-02 --- Several improvements to lexing and white space handling as suggested by Stephane Chazelas; continuation prompt support and whitespace handling improvements added by Any Webber.
* 2010-07-08 --- Hosting moved to GitHub. Note, hosting of examples at http://www.cpjobling.org.uk may not be stable.
===== To Do =====
* It would be nice to support end of line markers for long command strings
* Doesn't work for transcripts that have no prompt: e.g. executable scripts. Better to use the '''' tag for these.
===== Bugs =====
* Care needed for CLI's that use > to end a prompt -- done.
* Doesn't handle continuation prompts in shells that allow multi-line input. -- done (thanks to Andy Webber)
* Ruby's multiple output line decorators are likely to cause problems.
* Bound to be others ... this is my first DokuWiki plugin (actually it's my first attempt at PHP coding ^_^)
* following codes don't display right
# rpm -ivh darcs-1.0.9-3.fc6.i386.rpm
Preparing... ########################################### [100%]
1:darcs ########################################### [100%]
===== Comments Please =====
I modified the **_render_conversation** function to //remove// first and last blank lines, otherwise it produces two //blank excess output spans//.
if ( trim($lines[0]) == "" ) unset( $lines[0] );
if ( trim($lines[count($lines)]) == "" ) unset( $lines[count($lines)] );
This is just a quick hack and needs more afterthought, of course.
I also did not like the "empty lines got removed" effect, thus the **preg_split** line was also modified:
$lines = preg_split('/\n\r|\n|\r/',$match);
The previous comment still applies.
Added to new release ... CPJ