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

-- this is not a real parser as we also want to typeset wrong output
-- and a real parser would choke on that

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
--
-- depricated:
--
-- gcinfo unpack getfenv setfenv loadlib
-- table.maxn table.getn table.setn
-- math.log10 math.mod math.modf math.fmod

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", "loadfile",
    "loadstring", "print", "rawget", "rawset", "require", "tonumber",
    "tostring", "type",
}

visualizer.identifiers.five = {
    "_G", "getmetatable", "ipairs", "next", "pairs",
    "pcall", "rawequal", "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", "package.config",
    -- 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.max", "math.min", "math.pi", "math.pow",
    "math.rad", "math.random", "math.randomseed", "math.sin", "math.sqrt",
    "math.tan", "math.cosh", "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.concat", "table.foreach", "table.foreachi",
    "table.sort", "table.insert", "table.remove",
    "table.pack", "table.unpack",
    -- 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",
    -- bit
    -- ... todo ...
}

local known_words = { }

for k,v in next, visualizer.identifiers do
    for _,w in next, 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)

local function written(state,c,i)
    if c == " " then
        state = finish_state(state)
        texsprint(ctxcatcodes,"\\obs")
    elseif c == "\t" then
        state = finish_state(state)
        texsprint(ctxcatcodes,"\\obs")
        if buffers.visualizers.enabletab then
            texsprint(ctxcatcodes,rep("\\obs ",i%buffers.visualizers.tablength))
        end
    else
        texwrite(c)
    end
    return state, 0
end

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, i = nil, nil, 0
        for c in utfcharacters(code) do
            i = i + 1
            if instr then
                if p then
                    texwrite(p)
                    p = nil
                end
                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
                    state, i = written(state,c,i)
                end
            elseif c == "[" then
                if word then
                    texwrite(word)
                    word = nil
                end
                if p == "[" then
                    inlongstring = true
                    state = change_state(states["[["],state)
                    texwrite(p,c)
                    state = finish_state(state)
                    p = nil
                else
                    if p then
                        state, i = written(state,p,i)
                    end
                    p = c
                end
            elseif c == "]" then
                if word then
                    texwrite(word)
                    word = nil
                end
                if p == "]" then
                    inlongstring = false
                    state = change_state(states["]]"],state)
                    texwrite(p,c)
                    state = finish_state(state)
                    p = nil
                else
                    if p then
                        state, i = written(state,p,i)
                    end
                    p = c
                end
            else
                if p then
                    state = change_state(states[p],state)
                    texwrite(p)
                    state = finish_state(state)
                    p = nil
                end
                if c == " " or c == "\t" then
                    if word then
                        state = flush_lua_word(state,word)
                        word = nil
                    end
                    state, i = written(state,c,i)
                elseif inlongstring then
                    state, i = written(state,c,i)
                elseif c == '"' or c == "'" then
if word then
    state = flush_lua_word(state,word)
    word = nil
end
                    instr = true
                    state = change_state(states[c],state)
                    state, i = written(state,c,i)
                    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
        if p then
            texwrite(p)
            -- state, i = written(state,p,i)
            p = nil
        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
                state, i = written(state,c,i)
            end
        end
    end
    if comment then
        incomment = true
        state = change_state(states['--'], state)
        texwrite("[[")
        state = finish_state(state)
     -- texwrite(comment) -- maybe also split and
        for c in utfcharacters(comment) do
            state, i = written(state,c,i)
        end
    end
    state = finish_state(state)
end
