Below is the file 'syntax.py' from this revision. You can also download the file.

# Copyright (C) 2005 Grahame Bowland <grahame@angrygoats.net>
#
# This program is made available under the GNU GPL version 2.0 or
# greater. See the accompanying file COPYING for details.
#
# This program is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
# PURPOSE.

#!/usr/bin/env python2.4

from common import set_nonblocking, terminate_popen3
from web import debug
import config
import popen2
import select
import cgi

mime_to_lang = {

}

def highlight(*args, **kwargs):
    # if we don't have a highlighter, let's just return the original
    # iterator
    if not hasattr(config, "highlight_command"):
        return __basic_highlight(*args, **kwargs)
    else:
        return __highlight(*args, **kwargs)

def __basic_highlight(lines, language='py'):
    for line in lines:
        yield cgi.escape(line.rstrip('\n'))

def __highlight(lines, language='py'):
    """A generator which will read lines from the given input stream, and yield them back
    in syntax highlighted, HTML format. """

    # trickier than this initially looks; the syntax highlighter might not necessarily
    # have any more data for us, so it's necessary to use select() and write new data
    # as it wants it, and read it back (buffer and yield lines) as possible.
    #
    # this assumes the 'highlight' command, although shouldn't take much work to have this
    # happy with other highlighters.

    fromchild_buf, tochild_buf = '', ''
    to_run = [config.highlight_command, '--syntax', language, '-c', '/dev/null', '--quiet', '--xhtml', '--force', '--anchors', '--fragment']

    process = popen2.Popen3(to_run, capturestderr=True)
    map (set_nonblocking, [ process.fromchild,
                            process.tochild,
                            process.childerr ])
    while True:
        r_fds = [process.fromchild]
        w_fds = []
        if not process.tochild.closed:
            w_fds.append(process.tochild)
        r_stdin, r_stdout, r_stderr = select.select(r_fds, w_fds, [], None)
        # debug ((r_stdin, r_stdout, r_stderr))
        if not r_stdin and not r_stdout and not r_stderr:
            break
        if process.fromchild in r_stdin:
            data = process.fromchild.read()
            if data == "":
                break
            fromchild_buf += data

        if process.tochild in r_stdout:
            if tochild_buf == '':
                try:
                    tochild_buf += lines.next()
                except StopIteration:
                    tochild_buf = ''
            if tochild_buf == '':
                process.tochild.close()
            else:
                process.tochild.write(tochild_buf)
            tochild_buf = ''

        if fromchild_buf != '':
            while True:
                idx = fromchild_buf.find('\n')
                if idx == -1:
                    break
                yield fromchild_buf[:idx]
                fromchild_buf = fromchild_buf[idx+1:]

    # anything left over (presumably without a newline)
    if fromchild_buf != '':
        yield fromchild_buf

    terminate_popen3(process)

if __name__ == '__main__':
    def l():
        fd = open('syntax.py')
        for line in fd:
            yield line
    for i in highlight(l()):
        print i

###
### vi:expandtab:sw=4:ts=4
###