if not modules then modules = { } end modules ['pret-lua'] = {
    version   = 1.001,
    comment   = "companion to buff-ver.tex",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"
}

local utf = unicode.utf8

local utfcharacters, utfvalues = string.utfcharacters, string.utfvalues
local utfbyte, utffind = utf.byte, utf.find
local byte, sub, find, match = string.byte, string.sub, string.find, string.match
local texsprint, texwrite = tex.sprint, tex.write
local ctxcatcodes = tex.ctxcatcodes

local visualizer = buffers.newvisualizer("lua")

visualizer.identifiers = { }

-- borrowed from scite

visualizer.identifiers.core = {
    "and", "break", "do", "else", "elseif", "end", "false", "for", "function",
    "if", "in", "local", "nil", "not", "or", "repeat", "return", "then",
    "true", "until", "while"
}

visualizer.identifiers.base = {
    "assert", "collectgarbage", "dofile", "error", "gcinfo", "loadfile",
    "loadstring", "print", "rawget", "rawset", "require", "tonumber",
    "tostring", "type", "unpack",
}

visualizer.identifiers.five = {
    "_G", "getfenv", "getmetatable", "ipairs", "loadlib", "next", "pairs",
    "pcall", "rawequal", "setfenv", "setmetatable", "xpcall", "string", "table",
    "math", "coroutine", "io", "os", "debug", "load", "module", "select"
}

visualizer.identifiers.libs = {
    -- coroutine
    "coroutine.create", "coroutine.resume", "coroutine.status", "coroutine.wrap",
    "coroutine.yield", "coroutine.running",
    -- package
    "package.cpath", "package.loaded", "package.loadlib", "package.path",
    -- io
    "io.close", "io.flush", "io.input", "io.lines", "io.open", "io.output",
    "io.read", "io.tmpfile", "io.type", "io.write", "io.stdin", "io.stdout",
    "io.stderr", "io.popen",
    -- math
    "math.abs", "math.acos", "math.asin", "math.atan", "math.atan2", "math.ceil",
    "math.cos", "math.deg", "math.exp", "math.floor math.", "math.ldexp",
    "math.log", "math.log10", "math.max", "math.min math.mod math.pi", "math.pow",
    "math.rad", "math.random", "math.randomseed", "math.sin", "math.sqrt",
    "math.tan", "math.cosh", "math.fmod", "math.modf", "math.sinh", "math.tanh",
    "math.huge",
    -- string
    "string.byte", "string.char", "string.dump", "string.find", "string.len",
    "string.lower", "string.rep", "string.sub", "string.upper", "string.format",
    "string.gfind", "string.gsub", "string.gmatch", "string.match", "string.reverse",
    -- table
    "table.maxn", "table.concat", "table.foreach", "table.foreachi", "table.getn",
    "table.sort", "table.insert", "table.remove", "table.setn",
    -- os
    "os.clock", "os.date", "os.difftime", "os.execute", "os.exit", "os.getenv",
    "os.remove", "os.rename", "os.setlocale", "os.time", "os.tmpname",
    -- package
    "package.preload", "package.seeall"
}

local known_words = { }

for k,v in pairs(visualizer.identifiers) do
    for _,w in pairs(v) do
        known_words[w] = k
    end
end

visualizer.styles = {
    core = "",
    base = "\\sl ",
    five = "\\sl ",
    libs = "\\sl ",
}

local styles = visualizer.styles

local colors = {
    "prettyone",
    "prettytwo",
    "prettythree",
    "prettyfour",
}

local states = {
    ['"']=1, ["'"]=1, ["[["] = 1, ["]]"] = 1,
    ['+']=1, ['-']=1, ['*']=1, ['/']=1, ['%']=1, ['^']=1,
    ["("] = 3, [")"] = 3, ["["] = 3, ["]"] = 3,
    ['--']=4,
}

local change_state, finish_state = buffers.change_state, buffers.finish_state

local function flush_lua_word(state, word)
    if word then
        local id = known_words[word]
        if id then
            state = change_state(2,state)
            if styles[id] then
                texsprint(ctxcatcodes,styles[id])
            end
            texwrite(word)
            state = finish_state(state)
        else
            state = finish_state(state) -- ?
            texwrite(word)
        end
    else
        state = finish_state(state)
    end
    return state
end

local incomment, inlongstring = false, false

function visualizer.reset()
    incomment, inlongstring = false, false -- needs to be hooked into flusher
end

-- we will also provide a proper parser based pretty printer although normaly
-- a pretty printer should handle faulty code too (educational purposes)

function visualizer.flush_line(str, nested)
    local state, instr, inesc, word = 0, false, false, nil
    buffers.currentcolors = colors
    local code, comment = match(str,"^(.-)%-%-%[%[(.*)$")
    if comment then
        -- process the code and then flush the comment
    elseif incomment then
        comment, code = match(str,"^(.-)%]%](.*)$")
        if comment then
            -- flush the comment and then process the code
            for c in utfcharacters(comment) do
                if c == " " then texsprint(ctxcatcodes,"\\obs") else texwrite(c) end
            end
            state = change_state(states['--'], state)
            texwrite("]]")
            state = finish_state(state)
            incomment = false
        else
            for c in utfcharacters(str) do
                if c == " " then texsprint(ctxcatcodes,"\\obs") else texwrite(c) end
            end
        end
        comment = nil
    else
        code = str
    end
    if code and code ~= "" then
        local pre, post = match(code,"^(.-)%-%-(.*)$")
        if pre then
            code = pre
        end
        local p, s = nil, nil
        for c in utfcharacters(code) do
            if c == "[" then
                if p == "[" then
                    inlongstring = true
                    state = change_state(states["[["],state)
                    texwrite(p,c)
                    state = finish_state(state)
                    p = nil
                else
                    p = c
                end
            elseif c == "]" then
                if p == "]" then
                    inlongstring = false
                    state = change_state(states["]]"],state)
                    texwrite(p,c)
                    state = finish_state(state)
                    p = nil
                else
                    p = c
                end
            else
                if p then
                    state = change_state(states[c],state)
                    texwrite(p,c)
                    state = finish_state(state)
                    p = nil
                end
                if c == " " then
                    if word then
                        state = flush_lua_word(state,word)
                        word = nil
                    end
                    texsprint(ctxcatcodes,"\\obs")
                elseif inlongstring then
                    texwrite(c)
                elseif instr then
                    if c == s then
                        if inesc then
                            texwrite(c)
                            inesc = false
                        else
                            state = change_state(states[c],state)
                            instr = false
                            texwrite(c)
                            state = finish_state(state)
                        end
                        s = nil
                    else
                        if c == "\\" then
                            inesc = not inesc
                        else
                            inesc = false
                        end
                        texwrite(c)
                    end
                elseif c == '"' or c == "'" then
                    instr = true
                    state = change_state(states[c],state)
                    texwrite(c)
                    state = finish_state(state)
                    s = c
                elseif find(c,"^[%a]$") then
                    state = finish_state(state)
                    if word then word = word .. c else word = c end
                elseif word and (#word > 1) and find(c,"^[%d%.%_]$") then
                    if word then word = word .. c else word = c end
                else
                    state = flush_lua_word(state,word)
                    word = nil
                    state = change_state(states[c],state)
                    texwrite(c)
                    instr = (c == '"')
                end
            end
        end
        state = flush_lua_word(state,word)
        if post then
            state = change_state(states['--'], state)
            texwrite("--")
            state = finish_state(state)
            for c in utfcharacters(post) do
                if c == " " then texsprint(ctxcatcodes,"\\obs") else texwrite(c) end
            end
        end
    end
    if comment then
        incomment = true
        state = change_state(states['--'], state)
        texwrite("[[")
        state = finish_state(state)
        texwrite(comment)
    end
    state = finish_state(state)
end
