Custom Markup Cookbook

This is just a rough idea of things that can be done via the custom markup functionality of #301, #405 and #417. It'll be a work in progress.

To get a list of the custom markups available on any particular server, just include the {markups} markup in any Wiki page.

HTML Markup Shortcuts

Rather than having to do things like <html><big>text</big></html>, you can define markups as shortcuts (the HTML would go in the custom formatter section):

Emulating Other Wikis

Some wikis implement "verbatim" blocks. This can easily be done with a Block markup, {verbatim} which uses the following formatter:


To start a block, you'd use {verbatim} and to close it, {endverbatim}.

By itself, this doesn't buy you much beyond the default CVSTrac verbatim blocks (besides not having to indent large tracts), but you can adjust the HTML output to do things like add a contrasting background:

  <PRE STYLE="background: #e8e8e8">.

Or, if you wanted indentation too:

  <TABLE WIDTH="95%"><TR><TD> </TD><TD>
  <PRE STYLE="background: #e8e8e8">

As more and more browsers are supporting CSS widely, indentation would rather be done with:

  <PRE STYLE="background-color: #e8e8e8; margin-left: 1em">

(I'm afraid not. The first (original) example won't work, either. See #724. The HTML filters strips out the STYLE attribute (spammers like to embed stuff in wikis with explicit style attributes having a display:none;), so you'd actually have to use something like CLASS="indented" and augment the CVSTrac style sheet, or you'd need to do the markup via an external program which can be tagged as "trusted"-- cpb)

CVSTrac Shortcuts

Want a link into the CVS repository without a cumbersome URL? {getfile cvstrac/main.c} with @ <span class="%z(zMarkup)">\ }else{ @ <div class="%z(zMarkup)"> } <a href="getfile?f=%k"><tt>%x</tt></a>. The %x substitution allows you to use things like {getfile cvstrac/main.c} or {getfile cvstrac/main.c CVSTrac's main.c}.

Various tickets (#137, #122) have requested the ability to easily link to reports. A {rptview:n} markup can be easily added with <a href="rptview?rn=%k">%x</a> as a formatter.

External Resources

Most external resources will simply be markups as convenient links. The advantage of using a custom markup rather than {link:} markups or straight HTML is that if a service changes, you only have to change the custom markup.

CPAN module? {cpan: module} using <a href="">%x</a>.

An external resource section wouldn't be complete without {google: search terms} with <a href=" %a">%k %a</a>.

Program Markups

It's possible to write custom markups that call external programs. This isn't always a good idea (from a performance and security perspective), but it may be the only way to do some things. Note that some of these examples are simply that, examples, and have not be exhaustively auditted from a security perspective.

Trvial examples are markups which just run a command and spit out information. Date/time stamps, system information, etc. For example, a trivial {timestamp} markup would simply use /bin/date as a formatter with no substitution arguments.

A more complicated example is a markup to inline something from the CVS repository into the wiki page, such as {include: cvstrac/main.c}. Using the formatter /path/to/include '%r/%k', the following script could be used to inline the latest version of any file found under the repository:

  FILE=`/bin/echo $1 | /bin/sed 's/\.\.//g'`
  /bin/cat <<END
  <div style="background: #e8e8e8">
  `/usr/bin/co -q -p $FILE,v 2>/dev/null`

The really interesting markup happens when you start to interact with the SQLite database, allowing for things like custom reports and whatnot. The following script can be used to define a {wikitoc} markup using /path/to/wikitoc '%r/%n':

  for p in `sqlite $1.db 'SELECT name FROM wiki GROUP BY name ORDER BY name;'`
    echo "<a href=\"wiki?p=$p\">$p</a><br>"

Or, to list all the new and active tickets using an {activetkts} markup, the following script:

  for t in `sqlite $1.db 'SELECT tn FROM ticket \
    WHERE status IN ("new","active") ORDER BY tn;'`
    echo "<a href=\"tktview?tn=$t\">#$t</a> "

#449 shows a technique for embedded ticket status reports. In #724, Clay Dowling polishes it into something functional.

Note that some care should be made when writing such reports to ensure that the end results respect database access permissions for any given user. In other words, where it matters use the %c substitution. This could be a problem in the {include: <filename>} markup, for example.

Want to embed an RSS feed into a wiki? The following is a trivial perl script to implement a {rss: <uri>} markup:


  use XML::RSS;
  use LWP::Simple;

  my $rss = new XML::RSS;
  $rss->parse( get($ARGV[0]) );

  print qq(<DIV CLASS="rss">\n);
  for( @{$rss->{'items'}}) {
    print qq(<a href="$_->{'link'}">), $_->{'title'}, qq(</a><br>);
  print "</DIV>\n";

Program Blocks

One can also run arbitrary filters on markups blocks. This could be used for custom formatting as described in #353.

I'm still playing with the possibilities, but here's a scary thought... Create a {sqlite} program block using the following formatter:

  /usr/bin/sqlite '%r/%n.db'

Custom reports are just the tip of the iceberg, although from a security perspective it's outright insane.

A More Realistic Example

Periodically, a ticket like #402 may show up in a language not spoken by any maintainers. Or, like me, you work in a bilingual environment. A handy block markup is then {translate: <from> <to>} and {endtranslate} which translates a block of text from one language to another, outputting both. For example, when wrapped with {translate: es en} the text of #402 ends up looking like:

Esta es una prueba de Ticket ... NO LE DEN IMPORTANCIA y eliminenla :d @ <span class="%z(zMarkup)">\ }else{ @ <div class="%z(zMarkup)"> } Se agrego una linea a la descripcion: Se agrego una nueva marca
This is a test of Ticket... THEY DO NOT GIVE to IMPORTANCE and eliminenla HIM:d I add a line to the description: I add a new mark

Well, it's enough to get the idea. We use " %k %a" as a formatter with the following script:


  use Lingua::Translate;

  my $x = Lingua::Translate->new(src => $ARGV[0], dest => $ARGV[1]);
  my $from = join("",<STDIN>);
  print $from, "<BLOCKQUOTE>\n";
  print $x->translate($from);
  print "\n</BLOCKQUOTE>\n";