if not modules then modules = { } end modules ['pret-pas'] = { version = 1.0, comment = "custom pretty printer for Pascal code", author = "Stefan Müller, Chemnitz DE", copyright = "Stefan Müller", license = "see context related readme files" } -- The code formatting is adapted from Lazarus, a Free Pascal RAD IDE. -- http://lazarus.freepascal.org/ local visualizer = buffers.newvisualizer("pas") -- The list of reserved words is taken from -- http://www.freepascal.org/docs-html/ref/refse3.html visualizer.reservedwords = { -- Turbo Pascal "absolute", "and", "array", "asm", "begin", "case", "const", "constructor", "destructor", "div", "do", "downto", "else", "end", "file", "for", "function", "goto", "if", "implementation", "in", "inherited", "inline", "interface", "label", "mod", "nil", "not", "object", "of", "on", "operator", "or", "packed", "procedure", "program", "record", "reintroduce", "repeat", "self", "set", "shl", "shr", "string", "then", "to", "type", "unit", "until", "uses", "var", "while", "with", "xor", -- Free Pascal -- these are not bold type (keeping them, just in case) -- "dispose", "exit", "false", "new", "true", -- Object Pascal "as", "class", "dispinterface", "except", "exports", "finalization", "finally", "initialization", "inline", "is", "library", "on", "out", "packed", "property", "raise", "resourcestring", "threadvar", "try", -- Modifiers -- some of these are only bold in specific places (in the following, this is -- deliberately ignored) "absolute", "abstract", "alias", "assembler", "cdecl", "cppdecl", "default", "export", "external", "far", "far16", "forward", "index", "local", "name", "near", "nostackframe", "oldfpccall", "override", "pascal", "private", "protected", "public", "published", "read", "register", "reintroduce", "safecall", "softfloat", "stdcall", "virtual", "write" } local known_words = { } for k,v in next, visualizer.reservedwords do known_words[v] = k end local colors = { "prettyone", -- red: compiler directive, symbol "prettytwo", -- green: assembler (dark green) "prettythree", -- blue: comment, number (dark blue) "prettyfour", -- yellow } local states = { ['"']=1, ["'"]=1, ["[["] = 1, ["]]"] = 1, ['+']=1, ['-']=1, ['*']=1, ['/']=1, ['%']=1, ['^']=1, ["("] = 3, [")"] = 3, ["["] = 3, ["]"] = 3, ['--']=4, } local function flush_pas_word(word) if word then local id = known_words[string.lower(word)] if id then tex.sprint(tex.ctxcatcodes, "\{\\bf ") tex.write(word) tex.sprint(tex.ctxcatcodes, "\}") else tex.write(word) end end end local function flush_whatever(str) if str then for c in string.utfcharacters(str) do if c == " " then tex.sprint(tex.ctxcatcodes, "\\obs") elseif c == "\t" then tex.sprint(tex.ctxcatcodes, "\\obs") if buffers.visualizers.enabletab then tex.sprint(tex.ctxcatcodes,rep("\\obs ", buffers.visualizers.tablength)) end else tex.write(c); end end end end local inlongcomment, inlongcomment_alt, incompdirec, inasm = false, 0, false, false function visualizer.reset() inlongcomment, inlongcomment_alt, incompdirec, inasm = false, 0, false, false end --[[local function written(state, c, i) if c == " " then state = buffers.finishstate(state) tex.sprint(tex.ctxcatcodes,"\\obs") elseif c == "\t" then state = buffers.finishstate(state) tex.sprint(tex.ctxcatcodes,"\\obs") if buffers.visualizers.enabletab then tex.sprint(tex.ctxcatcodes,rep("\\obs ",i%buffers.visualizers.tablength)) end else tex.write(c) end return state, 0 end]] function visualizer.flush_line(str, nested) local state = 0 local incomment, instring = false, false --local code, comment = nil, nil buffers.currentcolors = colors --[[ print("SEARCHING FOR IDENTIFIERS IN: " .. str) local remain = str local identifier repeat identifier = nil identifier, remain = string.match(remain, "^[^%a_]*([%a_]+[%a%d_]*)(.*)$") if identifier then print("IDENTIFIER: " .. identifier) --print("REMAIN: " .. remain) end until not identifier ]] --TODO: handle inlongcomment etc. --[[ if inlongcomment then comment, code = string.match(str,"^(.-})(.*)$") if not comment then comment = str end state = buffers.changestate(3, state) tex.sprint(tex.ctxcatcodes, "\{\\bf") flush_whatever(comment) tex.sprint(tex.ctxcatcodes, "\}") if code then inlongcomment = false else code = "" end else code = str end ]] if inlongcomment or (inlongcomment_alt == 2) or incompdirec then incomment = true if incompdirec then state = buffers.changestate(1, state) else state = buffers.changestate(3, state) end tex.sprint(tex.ctxcatcodes, "\{\\bf") end local c, word = nil, nil for nextc in string.utfcharacters(str .. " ") do if c then if instring then if c == "'" then -- string ends tex.write(c) state = buffers.finishstate(state) instring = false else -- inside the string flush_whatever(c) end elseif incomment then if ((inlongcomment or incompdirec) and (c == "}")) or (inlongcomment_alt == 1) then -- long comment/(alternative)/compiler directive ends tex.write(c) tex.sprint(tex.ctxcatcodes, "\}") state = buffers.finishstate(state) incompdirec = false inlongcomment = false inlongcomment_alt = 0 incomment = false elseif (inlongcomment_alt == 2) and (c == "*") and (nextc == ")") then -- long comment (alternative) ends after nextc tex.write(c) inlongcomment_alt = 1 else -- inside the comment flush_whatever(c) end elseif string.find(c, "^[%a_]$") then -- char belongs to identifier if word then word = word .. c else word = c end elseif string.find(c, "^[%d]$") then if word and (#word > 1) then -- number, that belongs to identifier word = word .. c else -- number state = buffers.changestate(3, state) tex.write(c) end else state = buffers.finishstate(state) -- identifier complete, check if it's a reserved word and flush flush_pas_word(word) word = nil if c == " " then tex.sprint(tex.ctxcatcodes, "\\obs") elseif c == "\t" then tex.sprint(tex.ctxcatcodes, "\\obs") if buffers.visualizers.enabletab then tex.sprint(tex.ctxcatcodes,rep("\\obs ", buffers.visualizers.tablength)) end elseif c == "'" then -- string starts instring = true state = buffers.changestate(3, state) tex.write(c) elseif (c == "/") and (nextc == "/") then -- one-line comment starts incomment = true state = buffers.changestate(3, state) tex.sprint(tex.ctxcatcodes, "\{\\bf") tex.write(c) elseif c == "{" then incomment = true if nextc == "$" then -- compiler directive starts incompdirec = true state = buffers.changestate(1, state) else -- long comment starts inlongcomment = true state = buffers.changestate(3, state) end tex.sprint(tex.ctxcatcodes, "\{\\bf") tex.write(c) elseif (c == "(") and (nextc == "*") then -- long comment (alternative) starts incomment = true inlongcomment_alt = 2 state = buffers.changestate(3, state) tex.sprint(tex.ctxcatcodes, "\{\\bf") tex.write(c) -- TODO: asm else -- symbol state = buffers.changestate(1, state) tex.write(c) end end end c = nextc end if not incomment then state = buffers.finishstate(state) end -- maybe something left, check if it's a reserved word and flush flush_pas_word(word) if incomment then -- end the comment-line tex.sprint(tex.ctxcatcodes, "\}") end state = buffers.finishstate(state) --[[ local code, comment = string.match(str,"^(.-)%-%-%[%[(.*)$") if comment then -- process the code and then flush the comment elseif incomment then comment, code = string.match(str,"^(.-)%]%](.*)$") if comment then -- flush the comment and then process the code for c in string.utfcharacters(comment) do if c == " " then tex.sprint(tex.ctxcatcodes,"\\obs") else tex.write(c) end end state = buffers.changestate(states['--'], state) tex.write("KKK") state = buffers.finishstate(state) incomment = false else for c in string.utfcharacters(str) do if c == " " then tex.sprint(tex.ctxcatcodes,"\\obs") else tex.write(c) end end end comment = nil else code = str end if code and code ~= "" then local pre, post = string.match(code,"^(.-)%-%-(.*)$") if pre then code = pre end local p, s, i = nil, nil, 0 for c in string.utfcharacters(code) do i = i + 1 if instr then if p then tex.write(p) p = nil end if c == s then if inesc then tex.write(c) inesc = false else state = buffers.changestate(states[c],state) instr = false tex.write(c) state = buffers.finishstate(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 tex.write(word) word = nil end if p == "[" then inlongstring = true state = buffers.changestate(states["NRA"],state) tex.write(p,c) state = buffers.finishstate(state) p = nil else if p then state, i = written(state,p,i) end p = c end elseif c == "]" then if word then tex.write(word) word = nil end if p == "]" then inlongstring = false state = buffers.changestate(states["KKK"],state) tex.write(p,c) state = buffers.finishstate(state) p = nil else if p then state, i = written(state,p,i) end p = c end else if p then state = buffers.changestate(states[p],state) tex.write(p) state = buffers.finishstate(state) p = nil end if c == " " or c == "\t" then if word then flush_pas_word(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 flush_pas_word(word) word = nil end instr = true state = buffers.changestate(states[c],state) state, i = written(state,c,i) state = buffers.finishstate(state) s = c elseif string.find(c,"^[%a]$") then state = buffers.finishstate(state) if word then word = word .. c else word = c end elseif word and (#word > 1) and string.find(c,"^[%d%.%_]$") then if word then word = word .. c else word = c end else flush_pas_word(word) word = nil state = buffers.changestate(states[c],state) tex.write(c) instr = (c == '"') end end end if p then tex.write(p) -- state, i = written(state,p,i) p = nil end flush_pas_word(word) if post then state = buffers.changestate(states['--'], state) tex.write("--") state = buffers.finishstate(state) for c in string.utfcharacters(post) do state, i = written(state,c,i) end end end if comment then incomment = true state = buffers.changestate(states['--'], state) tex.write("NRA") state = buffers.finishstate(state) -- tex.write(comment) -- maybe also split and for c in string.utfcharacters(comment) do state, i = written(state,c,i) end end ]] state = buffers.finishstate(state) end