There are two main options available for highlighting text on a web site.  The first is to have the server perform the highlighting by using some or other external library, and the second option is to use client side highlighting via a Javascript app.

We chose server side for a variety of reasons. Firstly we wanted to demonstrate tinyMCE integration, and server side processing provides us with an ideal opportunity to do so.  Secondly, the overheads involved in client side highlighters may not be worth it, and Third we really liked the approach of the Pygments highlighter which is also Python and has a really snug fit with what we wanted.

Many wiki type sites or documentation sites use some form of markdown, for example Wikipedia's WikiEditor to produce HTML documents.  While these work quite well, we think the WYSIWYG approach of tinyMCE is really elegant and lowers the barrier to entry for producing HTML really fast.

There are numerous other popular visual editors available which we might have used, such as the CKEditor (formarly FCKEditor) or Wikipedia's new visual editor which is to replace WikiEditor.  TinyMCE is simple to integrate and does the job.

Source highlighter implementation

Looking at attachments.Source() implementation, the highlighter is called in the following method:

    def highlight(self):
        pygments = getUtility(ISourceHighlight, name="Pygments")
        return pygments(self.text, self.fmt)  # Returns highlighted text

Clearly, the variable pygments is being set to the utility exporting an ISourceHighlight interface with the name 'Pygments'.  The utility is then called with the text and the required format specifier.

The idea behind utilities, is that we can rather easily add alternative highlighters with the same interface by merely changing the name. This provides Grok with an astonishing amount of pluggability.

The utility we find is defined in the colourise.py source file as follows:

import pygments

class Pygments(grok.GlobalUtility):
    """ Implements a source code highlighter as a utility
    """
    grok.implements(ISourceHighlight)
    grok.name('Pygments')
    def __call__(self, data, fmt='python'):
        """  A highlighted version of the data is returned
        """
        lexer = pygments.get_lexer_by_name(fmt)
        formatter = pygments.get_formatter_by_name('html')
        return pygments.highlight(data, lexer, formatter)

Another global utility defines the list of available syntax highlighter formats as a vocabulary.  Vocabularies are rather powerful constructs which are well worth the effort spent learning about them.

class PygmentFormats(grok.GlobalUtility):
    """  The supported formats for our <pygmentize> based conversions
            *** NOTE *** Unsure why, but vocabularies defined like this
               need zope.app.schema in setup.py
    """
    grok.implements(IVocabularyFactory)
    grok.name('gfn.pygmentFormats')

    formats = [('html',       u'HTML Source'),
               ('javascript', u'Javascript Code'),
               ('python',     u'Python Sources'),
               ('css',        u'CSS Source'),
               ('xml',        u'Generic XML Source')]

    def __call__(self, context):
        self.context = context
        terms = []
        for value, title in self.formats:
            token  = str(value)
            terms.append(SimpleVocabulary.createTerm(value,token,title))
        return SimpleVocabulary(terms)

The above vocabulary is specified as a source in the 'fmt' attribute for the IAttachment interface schema class.

Grok 4 Noobs

Adding syntax highlighting