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, which -- should be quite similar to the Delphi style. Please note that comments are -- not typeset with bold fontface but slanted, which improves output when not -- using colors. -- 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 reserved_style = "\{\\bf " local comment_style = "\{\\sl " local inlongcomment, inlongcomment_alt, incompdirec, inasm = false, 0, false, false local function flush_pas_word(word, state) if word then local lword = string.lower(word) local id = known_words[lword] if id then if inasm and (lword == "end") then -- asm mode ends state = buffers.finishstate(state) inasm = false print("leave asm") end if not inasm then tex.sprint(tex.ctxcatcodes, reserved_style) tex.write(word) tex.sprint(tex.ctxcatcodes, "\}") if lword == "asm" then -- asm mode begins print("enter asm") inasm = true state = buffers.changestate(2, state) end else tex.write(word) end else tex.write(word) end end return state 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 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, comment_style) elseif inasm then state = buffers.changestate(2, state) 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, "\}") if inasm then -- resume to asm mode state = buffers.changestate(2, state) else state = buffers.finishstate(state) end 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 if not inasm then -- number state = buffers.changestate(3, state) end tex.write(c) end else if not inasm then state = buffers.finishstate(state) end -- identifier complete, check if it's a reserved word and flush state = flush_pas_word(word, state) 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 if not inasm then -- string begins instring = true state = buffers.changestate(3, state) end tex.write(c) elseif (c == "/") and (nextc == "/") then -- one-line comment begins incomment = true state = buffers.changestate(3, state) tex.sprint(tex.ctxcatcodes, comment_style) tex.write(c) elseif c == "{" then incomment = true if nextc == "$" then -- compiler directive begins incompdirec = true state = buffers.changestate(1, state) else -- long comment begins inlongcomment = true state = buffers.changestate(3, state) end tex.sprint(tex.ctxcatcodes, comment_style) tex.write(c) elseif (c == "(") and (nextc == "*") then -- long comment (alternative) begins incomment = true inlongcomment_alt = 2 state = buffers.changestate(3, state) tex.sprint(tex.ctxcatcodes, comment_style) tex.write(c) else if not inasm then -- symbol state = buffers.changestate(1, state) end tex.write(c) end end end c = nextc end if not incomment and not inasm then state = buffers.finishstate(state) end -- maybe something left, check if it's a reserved word and flush state = flush_pas_word(word, state) 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