if not modules then modules = { } end modules ['mtx-vscode'] = { version = 1.000, comment = "this script is experimental", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", copyright = "PRAGMA ADE", license = "see context related readme files" } -- todo: folding and comments -- todo: runners (awaiting global script setup) -- todo: dark theme -- Already for quite a while lexing in ConTeXt is kind of standardized and the way -- the format evolved also relates to how I see the source. We started with lexing -- beginning of 1990 with texedit/wdt in Modula2 and went via perltk (texwork), -- Scite (native), Scite (lpeg) as well as different stages in verbatim. So, as -- github uses VSCODE I decided to convert the couple of base lexers to the format -- that this editor likes. It's all about habits and consistency, not about tons of -- fancy features that I don't need and would not use anyway. -- -- I use a lua script to generate the lexer definitions simply because that way the -- update will be in sync with the updates in the context distribution. -- -- code.exe --extensions-dir e:\vscode\extensions --install-extension context -- -- In the end all these systems look alike so again we we have these token onto -- styling mappings. We even have embedded lexers. Actually, when reading the -- explanations it has become internally more close to what scintilla does with -- tokens and numbers related to it but then mapped back onto css. -- -- Multiline lexing is a pain here, so I just assume that stuff belonging together is -- on one line (like keys to simple values). I'm not in the mood for ugly multistep -- parsing now. Here the lpeg lexers win. -- -- We can optimize these expressions if needed but it all looks fast enough. Anyway, -- we do start from the already old lexers that we use in SciTe. The lexing as well -- as use of colors is kind of consistent and standardized in context and I don't -- want to change it. The number of colors is not that large and (at least to me) it -- looks less extreme. We also use a gray background because over time we figured -- out that this works best (1) for long sessions, and (2) for colors. We have quite -- some embedding so that is another reason for consistency. -- -- I do remember generating plist files many years ago but stopped doing that -- because I never could check them in practice. We're now kind of back to that. The -- reason for using a lua script to generate the json file is that it is easier to -- keep in sync with context and also because then a user can just generate the -- extension her/himself. -- -- There are nice examples of lexer definitions in the vc extensions path. My regexp -- experiences are somewhat rusted and I don't really have intentions to spend too -- much time on them. Compared to the lpeg lexers the regexp based ones are often -- more compact. It's just a different concept. Anyway, I might improve things after -- I've read more of the specs (it seems like the regexp engine is the one from ruby). -- We normally use a light gray background with rather dark colors which at least -- for us is less tiresome. The problem with dark backgrounds is that one needs to -- use light colors from pastel palettes. I need to figure out a mapping that works -- for a dark background so that optionally one can install without color theme. -- It is possible to define tasks and even relate them to languages but for some reason -- it can not be done global but per workspace which makes using vscode no option for -- me (too many different folders with source code, documentation etc). It's kind of -- strange because simple runners are provided by many editors. I don't want to program -- a lot to get such simple things done so, awaiting global tasks I stick to using the -- terminal. But we're prepared. -- Another showstopper is the fact that we cannot disable utf8 for languages (like pdf, -- which is just bytes). I couldn't figure out how to set it in the extension. -- { -- "window.zoomLevel": 2, -- "editor.renderWhitespace": "all", -- "telemetry.enableCrashReporter": false, -- "telemetry.enableTelemetry": false, -- "editor.fontFamily": "Dejavu Sans Mono, Consolas, 'Courier New', monospace", -- "window.autoDetectHighContrast": false, -- "zenMode.hideLineNumbers": false, -- "zenMode.centerLayout": false, -- "zenMode.fullScreen": false, -- "zenMode.hideTabs": false, -- "workbench.editor.showIcons": false, -- "workbench.settings.enableNaturalLanguageSearch": false, -- "window.enableMenuBarMnemonics": false, -- "search.location": "panel", -- "breadcrumbs.enabled": false, -- "workbench.activityBar.visible": false, -- "editor.minimap.enabled": false, -- "workbench.iconTheme": null, -- "extensions.ignoreRecommendations": true, -- "editor.renderControlCharacters": true, -- "terminal.integrated.scrollback": 5000, -- "workbench.colorTheme": "ConTeXt", -- "[context.cld]": {}, -- "terminal.integrated.fontSize": 10, -- "terminal.integrated.rendererType": "dom", -- "workbench.colorCustomizations": { -- "terminal.ansiBlack": "#000000", -- "terminal.ansiWhite": "#FFFFFF", -- "terminal.ansiRed": "#7F0000", -- "terminal.ansiGreen": "#007F00", -- "terminal.ansiBlue": "#00007F", -- "terminal.ansiMagenta": "#7F007F", -- "terminal.ansiCyan": "#007F7F", -- "terminal.ansiYellow": "#7F7F00", -- "terminal.ansiBrightBlack": "#000000", -- "terminal.ansiBrightWhite": "#FFFFFF", -- "terminal.ansiBrightRed": "#7F0000", -- "terminal.ansiBrightGreen": "#007F00", -- "terminal.ansiBrightBlue": "#00007F", -- "terminal.ansiBrightMagenta": "#7F007F", -- "terminal.ansiBrightCyan": "#007F7F", -- "terminal.ansiBrightYellow": "#7F7F00", -- } -- } -- kind of done: -- -- tex mps lua cld bibtex sql bnf(untested) pdf xml json c(pp)(simplified) -- -- unlikely to be done (ok, i'm not interested in all this ide stuff anyway): -- -- cpp-web tex-web web web-snippets txt -- -- still todo: -- -- xml: preamble and dtd -- pdf: nested string (..(..)..) local helpinfo = [[ mtx-vscode vscode extension generator 1.00 generate extension in sync with current version start vscode with extension context Example mtxrun --script vscode --generate e:/vscode/extensions mtxrun --script vscode --generate mtxrun --script vscode --start ]] local application = logs.application { name = "mtx-vscode", banner = "vscode extension generator", helpinfo = helpinfo, } local report = application.report require("util-jsn") scripts = scripts or { } scripts.vscode = scripts.vscode or { } local readmedata = [[ These files are generated. You can use these extensions with for instance: code.exe --extensions-dir /tex/texmf-context/context/data/vscode/extensions --install-extension context There are examples of scripts and keybindings too. ]] local function locate() local name = resolvers.findfile("vscode-context.readme") if name and name ~= "" then local path = file.dirname(file.dirname(name)) if lfs.isdir(path) then return path end end end function scripts.vscode.generate(targetpath) local targetpath = targetpath or environment.files[1] or locate() if not targetpath or targetpath == "" or not lfs.isdir(targetpath) then report("invalid targetpath %a",targetpath) return end local contextpath = string.gsub(targetpath,"\\","/") .. "/context" dir.makedirs(contextpath) if not lfs.chdir(contextpath) then return end local syntaxpath = contextpath .. "/syntaxes" local themepath = contextpath .. "/themes" local taskpath = contextpath .. "/tasks" local keybindingpath = contextpath .. "/keybindings" local settingspath = contextpath .. "/settings" dir.makedirs(syntaxpath) dir.makedirs(themepath) dir.makedirs(taskpath) dir.makedirs(keybindingpath) dir.makedirs(settingspath) if not lfs.isdir(syntaxpath) then return end if not lfs.isdir(themepath) then return end if not lfs.isdir(taskpath) then return end if not lfs.isdir(keybindingpath) then return end if not lfs.isdir(settingspath) then return end -- The package. local languages = { } local grammars = { } local themes = { } local tasks = { } local keybindings = { } local function registerlexer(lexer) local category = lexer.category local contextid = "context." .. category local scope = "source." .. contextid local setupfile = "./settings/context-settings-" .. category .. ".json" local grammarfile = "./syntaxes/context-syntax-" .. category .. ".json" local grammar = utilities.json.tojson { name = contextid, scopeName = scope, version = lexer.version, repository = lexer.repository, patterns = lexer.patterns, } local setup = utilities.json.tojson(lexer.setup) local suffixes = lexer.suffixes or { } local extensions = { } for i=1,#suffixes do extensions[i] = "." .. string.gsub(suffixes[i],"%.","") end table.sort(extensions) languages[#languages+1] = { id = contextid, extensions = #extensions > 0 and extensions or nil, aliases = { lexer.description }, configuration = setupfile, } grammars[#grammars+1] = { language = contextid, scopeName = "source." .. contextid, path = grammarfile, } report("saving grammar for %a in %a",category,grammarfile) report("saving setup for %a in %a",category,setupfile) io.savedata(grammarfile, grammar) io.savedata(setupfile, setup) end local function registertheme(theme) local category = theme.category local filename = "./themes/" .. category .. ".json" themes[#themes+1] = { label = theme.description, uiTheme = "vs", path = filename, } local data = utilities.json.tojson { ["$schema"] = "vscode://schemas/color-theme", ["name"] = category, ["colors"] = theme.colors, ["tokenColors"] = theme.styles, } report("saving theme %a in %a",category,filename) io.savedata(filename,data) end local function registertask(task) local category = task.category local filename = "./tasks/" .. category .. ".json" tasks[#tasks+1] = { label = task.description, path = filename, } local data = utilities.json.tojson { ["name"] = category, ["tasks"] = task.tasks, } report("saving task %a in %a",category,filename) io.savedata(filename,data) end local function registerkeybinding(keybinding) local bindings = keybinding.keybindings if bindings then local category = keybinding.category local filename = "./keybindings/" .. category .. ".json" report("saving keybinding %a in %a",category,filename) io.savedata(filename,utilities.json.tojson(bindings)) for i=1,#bindings do keybindings[#keybindings+1] = bindings[i] end end end local function savepackage() local packagefile = "package.json" local whateverfile = "package.nls.json" local readmefile = "vscode-context.readme" local specification = utilities.json.tojson { name = "context", displayName = "ConTeXt", description = "ConTeXt Syntax Highlighting", publisher = "ConTeXt Development Team", version = "1.0.0", engines = { vscode = "*" }, categories = { "Lexers", "Syntaxes" }, contributes = { languages = languages, grammars = grammars, themes = themes, tasks = tasks, keybindings = keybindings, }, } report("saving package in %a",packagefile) io.savedata(packagefile,specification) local whatever = utilities.json.tojson { displayName = "ConTeXt", description = "Provides syntax highlighting and bracket matching in ConTeXt files.", } report("saving whatever in %a",whateverfile) io.savedata(whateverfile,whatever) report("saving readme in %a",readmefile) io.savedata(readmefile,readmedata) end -- themes do local mycolors = { red = "#7F0000", green = "#007F00", blue = "#00007F", cyan = "#007F7F", magenta = "#7F007F", yellow = "#7F7F00", orange = "#B07F00", white = "#FFFFFF", light = "#CFCFCF", grey = "#808080", dark = "#4F4F4F", black = "#000000", selection = "#F7F7F7", logpanel = "#E7E7E7", textpanel = "#CFCFCF", linepanel = "#A7A7A7", tippanel = "#444444", right = "#0000FF", wrong = "#FF0000", } local colors = { ["editor.background"] = mycolors.textpanel, ["editor.foreground"] = mycolors.black, ["editorLineNumber.foreground"] = mycolors.black, ["editorIndentGuide.background"] = mycolors.textpanel, ["editorBracketMatch.background"] = mycolors.textpanel, ["editorBracketMatch.border"] = mycolors.orange, ["editor.lineHighlightBackground"] = mycolors.textpanel, ["focusBorder"] = mycolors.black, ["activityBar.background"] = mycolors.black, ["sideBar.background"] = mycolors.linepanel, ["sideBar.foreground"] = mycolors.black, ["sideBar.border"] = mycolors.white, ["sideBarTitle.foreground"] = mycolors.black, ["sideBarSectionHeader.background"] = mycolors.linepanel, ["sideBarSectionHeader.foreground"] = mycolors.black, ["statusBar.foreground"] = mycolors.black, ["statusBar.background"] = mycolors.linepanel, ["statusBar.border"] = mycolors.white, ["statusBar.noFolderForeground"] = mycolors.black, ["statusBar.noFolderBackground"] = mycolors.linepanel, ["statusBar.debuggingForeground"] = mycolors.black, ["statusBar.debuggingBackground"] = mycolors.linepanel, ["notification.background"] = mycolors.black, } local styles = { { scope = "context.whitespace", settings = { } }, { scope = "context.default", settings = { foreground = mycolors.black } }, { scope = "context.number", settings = { foreground = mycolors.cyan } }, { scope = "context.comment", settings = { foreground = mycolors.yellow } }, { scope = "context.keyword", settings = { foreground = mycolors.blue, fontStyle = "bold" } }, { scope = "context.string", settings = { foreground = mycolors.magenta } }, { scope = "context.error", settings = { foreground = mycolors.red } }, { scope = "context.label", settings = { foreground = mycolors.red, fontStyle = "bold" } }, { scope = "context.nothing", settings = { } }, { scope = "context.class", settings = { foreground = mycolors.black, fontStyle = "bold" } }, { scope = "context.function", settings = { foreground = mycolors.black, fontStyle = "bold" } }, { scope = "context.constant", settings = { foreground = mycolors.cyan, fontStyle = "bold" } }, { scope = "context.operator", settings = { foreground = mycolors.blue } }, { scope = "context.regex", settings = { foreground = mycolors.magenta } }, { scope = "context.preprocessor", settings = { foreground = mycolors.yellow, fontStyle = "bold" } }, { scope = "context.tag", settings = { foreground = mycolors.cyan } }, { scope = "context.type", settings = { foreground = mycolors.blue } }, { scope = "context.variable", settings = { foreground = mycolors.black } }, { scope = "context.identifier", settings = { } }, { scope = "context.linenumber", settings = { background = mycolors.linepanel } }, { scope = "context.bracelight", settings = { foreground = mycolors.orange, fontStyle = "bold" } }, { scope = "context.bracebad", settings = { foreground = mycolors.orange, fontStyle = "bold" } }, { scope = "context.controlchar", settings = { } }, { scope = "context.indentguide", settings = { foreground = mycolors.linepanel, back = colors.white } }, { scope = "context.calltip", settings = { foreground = mycolors.white, back = colors.tippanel } }, { scope = "context.invisible", settings = { background = mycolors.orange } }, { scope = "context.quote", settings = { foreground = mycolors.blue, fontStyle = "bold" } }, { scope = "context.special", settings = { foreground = mycolors.blue } }, { scope = "context.extra", settings = { foreground = mycolors.yellow } }, { scope = "context.embedded", settings = { foreground = mycolors.black, fontStyle = "bold" } }, { scope = "context.char", settings = { foreground = mycolors.magenta } }, { scope = "context.reserved", settings = { foreground = mycolors.magenta, fontStyle = "bold" } }, { scope = "context.definition", settings = { foreground = mycolors.black, fontStyle = "bold" } }, { scope = "context.okay", settings = { foreground = mycolors.dark } }, { scope = "context.warning", settings = { foreground = mycolors.orange } }, { scope = "context.standout", settings = { foreground = mycolors.orange, fontStyle = "bold" } }, { scope = "context.command", settings = { foreground = mycolors.green, fontStyle = "bold" } }, { scope = "context.internal", settings = { foreground = mycolors.orange, fontStyle = "bold" } }, { scope = "context.preamble", settings = { foreground = mycolors.yellow } }, { scope = "context.grouping", settings = { foreground = mycolors.red } }, { scope = "context.primitive", settings = { foreground = mycolors.blue, fontStyle = "bold" } }, { scope = "context.plain", settings = { foreground = mycolors.dark, fontStyle = "bold" } }, { scope = "context.user", settings = { foreground = mycolors.green } }, { scope = "context.data", settings = { foreground = mycolors.cyan, fontStyle = "bold" } }, { scope = "context.text", settings = { foreground = mycolors.black } }, { scope = { "emphasis" }, settings = { fontStyle = "italic" } }, { scope = { "strong" }, settings = { fontStyle = "bold" } }, { scope = { "comment" }, settings = { foreground = mycolors.black } }, { scope = { "string" }, settings = { foreground = mycolors.magenta } }, { scope = { "constant.numeric", "constant.language.null", "variable.language.this", "support.type.primitive", "support.function", "support.variable.dom", "support.variable.property", "support.variable.property", "meta.property-name", "meta.property-value", "support.constant.handlebars" }, settings = { foreground = mycolors.cyan, } }, { scope = { "keyword", "storage.modifier", "storage.type", "variable.parameter" }, settings = { foreground = mycolors.blue, fontStyle = "bold", } }, { scope = { "entity.name.type", "entity.other.inherited-class", "meta.function-call", "entity.other.attribute-name", "entity.name.function.shell" }, settings = { foreground = mycolors.black, } }, { scope = { "entity.name.tag", }, settings = { foreground = mycolors.black, } }, } registertheme { category = "context", description = "ConTeXt", colors = colors, styles = styles, } end do local presentation = { echo = true, reveal = "always", focus = false, panel = "shared", showReuseMessage = false, clear = true, } local tasks = { { group = "build", label = "process tex file", type = "shell", command = "context --autogenerate --autopdf ${file}", windows = { command = "chcp 65001 ; context.exe --autogenerate --autopdf ${file}" }, }, { group = "build", label = "check tex file", type = "shell", command = "mtxrun --autogenerate --script check ${file}", windows = { command = "chcp 65001 ; mtxrun.exe --autogenerate --script check ${file}" }, }, { group = "build", label = "identify fonts", type = "shell", command = "mtxrun --script fonts --reload --force", windows = { command = "chcp 65001 ; mtxrun.exe --script fonts --reload --force" }, }, { group = "build", label = "process lua file", type = "shell", command = "mtxrun --script ${file}", windows = { command = "chcp 65001 ; mtxrun.exe --script ${file}" }, }, } for i=1,#tasks do local task = tasks[i] if not task.windows then task.windows = { command = "chcp 65001 ; " .. task.command } end if not task.presentation then task.presentation = presentation end end registertask { category = "context", description = "ConTeXt Tasks", tasks = tasks, } end do local keybindings = { { -- runner = "context --autogenerate --autopdf ${file}", key = "ctrl-F12", command = "workbench.action.tasks.runTask", args = "process tex file", when = "editorTextFocus && editorLangId == context.tex", }, { -- runner = "mtxrun --autogenerate --script check ${file}", key = "F12", command = "workbench.action.tasks.runTask", args = "check tex file", when = "editorTextFocus && editorLangId == context.tex", }, { -- runner = "mtxrun --script ${file}", key = "ctrl-F12", command = "workbench.action.tasks.runTask", args = "process lua file", when = "editorTextFocus && editorLangId == context.cld", } } registerkeybinding { category = "context", description = "ConTeXt Keybindings", keybindings = keybindings, } end -- helpers local function loaddefinitions(name) return table.load(resolvers.findfile(name)) end local escapes = { ["."] = "\\.", ["-"] = "\\-", ["+"] = "\\+", ["*"] = "\\*", ['"'] = '\\"', ["'"] = "\\'", ['^'] = '\\^', ['$'] = '\\$', ["|"] = "\\|", ["\\"] = "\\\\", ["["] = "\\[", ["]"] = "\\]", ["("] = "\\(", [")"] = "\\)", ["%"] = "\\%", ["!"] = "\\!", ["&"] = "\\&", ["?"] = "\\?", ["~"] = "\\~", } local function sorter(a,b) return a > b end local function oneof(t) local result = { } table.sort(t,sorter) for i=1,#t do result[i] = string.gsub(t[i],".",escapes) end return table.concat(result,"|") end local function capture(str) return "(" .. str .. ")" end local function captures(str) return "\\*(" .. str .. ")\\*" end local function include(str) return { include = str } end local function configuration(s) if s then local pairs = s.pairs local comments = s.comments return { brackets = pairs, autoClosingPairs = pairs, surroundingPairs = pairs, comments = { lineComment = comments and comments.inline or nil, blockComment = comments and comments.display or nil, }, } else return { } end end -- I need to figure out a decent mapping for dark as the defaults are just -- not to my taste and we also have a different categorization. local mapping = { ["context.default"] = "text source", ["context.number"] = "constant.numeric", ["context.comment"] = "comment", ["context.keyword"] = "keyword", ["context.string"] = "string source", ["context.label"] = "meta.tag", ["context.constant"] = "support.constant", ["context.operator"] = "keyword.operator.js", ["context.identifier"] = "support.variable", ["context.quote"] = "string", ["context.special"] = "unset", ["context.extra"] = "unset", ["context.embedded"] = "meta.embedded", ["context.reserved"] = "unset", ["context.definition"] = "keyword", ["context.warning"] = "invalid", ["context.command"] = "unset", ["context.grouping"] = "unset", ["context.primitive"] = "keyword", ["context.plain"] = "unset", ["context.user"] = "unset", ["context.data"] = "text source", ["context.text"] = "text source", } local function styler(namespace) local done = { } local style = function(what,where) if not what or not where then report() report("? %-5s %-20s %s",namespace,what or "?",where or "?") report() os.exit() end -- if mapping then -- what = mapping[what] or what -- end local hash = what .. "." .. where if done[hash] then report("- %-5s %-20s %s",namespace,what,where) else -- report("+ %-5s %-20s %s",namespace,what,where) done[hash] = true end return hash .. "." .. namespace end return style, function(what,where) return { name = style(what, where) } end end local function embedded(name) return { { include = "source.context." .. name } } end -- The tex lexer. do local interface_lowlevel = loaddefinitions("scite-context-data-context.lua") local interface_interfaces = loaddefinitions("scite-context-data-interfaces.lua") local interface_tex = loaddefinitions("scite-context-data-tex.lua") local constants = interface_lowlevel.constants local helpers = interface_lowlevel.helpers local interfaces = interface_interfaces.common local primitives = { } local overloaded = { } for i=1,#helpers do overloaded[helpers[i]] = true end for i=1,#constants do overloaded[constants[i]] = true end local function add(data) for k, v in next, data do if v ~= "/" and v ~= "-" then if not overloaded[v] then primitives[#primitives+1] = v end v = "normal" .. v if not overloaded[v] then primitives[#primitives+1] = v end end end end add(interface_tex.tex) add(interface_tex.etex) add(interface_tex.pdftex) add(interface_tex.aleph) add(interface_tex.omega) add(interface_tex.luatex) add(interface_tex.xetex) local luacommands = { "ctxlua", "ctxcommand", "ctxfunction", "ctxlatelua", "ctxlatecommand", "cldcommand", "cldcontext", "luaexpr", "luascript", "luathread", "directlua", "latelua", } local luaenvironments = { "luacode", "luasetups", "luaparameterset", "ctxfunction", "ctxfunctiondefinition", } local mpscommands = { "reusableMPgraphic", "usableMPgraphic", "uniqueMPgraphic", "uniqueMPpagegraphic", "useMPgraphic", "reuseMPgraphic", "MPpositiongraphic", } local mpsenvironments_o = { "MPpage" } local mpsenvironments_a = { "MPcode", "useMPgraphic", "reuseMPgraphic", "MPinclusions", "MPinitializations", "MPdefinitions", "MPextensions", "MPgraphic", "MPcalculation", } -- clf_a-zA-z_ -- btx|xml a-z -- a-z btx|xml a-z -- mp argument {...text} local function words(list) table.sort(list,sorter) return "\\\\(" .. table.concat(list,"|") .. ")" .. "(?=[^a-zA-Z])" end local function bwords(list) table.sort(list,sorter) return "(\\\\(" .. table.concat(list,"|") .. "))\\s*(\\{)" end local function ewords() return "(\\})" end local function environments(list) table.sort(list,sorter) last = table.concat(list,"|") if #list > 1 then last = "(?:" .. last .. ")" end return capture("\\\\start" .. last), capture("\\\\stop" .. last) end local capturedconstants = words(constants) local capturedprimitives = words(primitives) local capturedhelpers = words(helpers) local capturedcommands = words(interfaces) local capturedmpscommands = words(mpscommands) local spaces = "\\s*" local identifier = "[a-zA-Z\\_@!?\127-\255]+" local comment = "%.*$\\n?" local ifprimitive = "\\\\if[a-zA-Z\\_@!?\127-\255]*" local csname = "\\\\[a-zA-Z\\_@!?\127-\255]+" local csprefix = "\\\\(btx|xml)[a-z]+" local cssuffix = "\\\\[a-z]+(btx|xml)[a-z]*" local csreserved = "\\\\(\\?\\?|[a-z]\\!)[a-zA-Z\\_@!?\127-\255]+" local luaenvironmentopen, luaenvironmentclose = environments(luaenvironments) local luacommandopen, luacommandclose = environments(luacommands) local mpsenvironmentopen_o, mpsenvironmentclose_o = environments(mpsenvironments_o) local mpsenvironmentopen_a, mpsenvironmentclose_a = environments(mpsenvironments_a) local argumentopen = capture("\\{") local argumentclose = capture("\\}") local argumentcontent = capture("[^\\}]*") local optionopen = capture("\\[") local optionclose = capture("\\]") local optioncontent = capture("[^\\]]*") -- not ok yet, todo: equal in settings .. but it would become quite ugly, lpeg wins here -- so instead we color differently local option = "(?:" .. optionopen .. optioncontent .. optionclose .. ")?" local argument = "(?:" .. argumentopen .. argumentcontent .. argumentclose .. ")?" local mpsenvironmentopen_o = mpsenvironmentopen_o .. spaces .. option .. spaces .. option local mpsenvironmentopen_a = mpsenvironmentopen_a .. spaces .. argument .. spaces .. argument local style, styled = styler("tex") local capturedgroupings = oneof { "{", "}", "$" } local capturedextras = oneof { "~", "%", "^", "&", "_", "-", "+", "/", "'", "`", "\\", "|", } local capturedspecials = oneof { "(", ")", "[", "]", "<", ">", "#", "=", '"', } local capturedescaped = "\\\\." registerlexer { category = "tex", description = "ConTeXt TEX", suffixes = { "tex", "mkiv", "mkvi", "mkix", "mkxi", "mkil", "mkli", "mkii" }, version = "1.0.0", setup = configuration { pairs = { { "{", "}" }, { "[", "]" }, { "(", ")" }, }, comments = { inline = "%", }, }, repository = { comment = { name = style("context.comment", "comment"), match = texcomment, }, constant = { name = style("context.constant", "commands.constant"), match = capturedconstants, }, ifprimitive = { name = style("context.primitive", "commands.if"), match = ifprimitive, }, primitive = { name = style("context.primitive", "commands.primitive"), match = capturedprimitives, }, helper = { name = style("context.plain", "commands.plain"), match = capturedhelpers, }, command = { name = style("context.command", "commands.context"), match = capturedcommands, }, csname = { name = style("context.user", "commands.user"), match = csname, }, escaped = { name = style("context.command", "commands.escaped"), match = capturedescaped, }, subsystem_prefix = { name = style("context.embedded", "subsystem.prefix"), match = csprefix, }, subsystem_suffix = { name = style("context.embedded", "subsystem.suffix"), match = cssuffix, }, grouping = { name = style("context.grouping", "symbols.groups"), match = capturedgroupings, }, extra = { name = style("context.extra", "symbols.extras"), match = capturedextras, }, special = { name = style("context.special", "symbols.special"), match = capturedspecials, }, reserved = { name = style("context.reserved", "commands.reserved"), match = csreserved, }, lua_environment = { ["begin"] = luaenvironmentopen, ["end"] = luaenvironmentclose, patterns = embedded("cld"), beginCaptures = { ["0"] = styled("context.embedded", "lua.environment.open") }, endCaptures = { ["0"] = styled("context.embedded", "lua.environment.close") }, }, lua_command = { ["begin"] = luacommandopen, ["end"] = luacommandclose, patterns = embedded("cld"), beginCaptures = { ["1"] = styled("context.embedded", "lua.command.open"), ["2"] = styled("context.grouping", "lua.command.open"), }, endCaptures = { ["1"] = styled("context.grouping", "lua.command.close"), }, }, metafun_environment_o = { ["begin"] = mpsenvironmentopen_o, ["end"] = mpsenvironmentclose_o, patterns = embedded("mps"), beginCaptures = { ["1"] = styled("context.embedded", "metafun.environment.start.o"), ["2"] = styled("context.embedded", "metafun.environment.open.o.1"), ["3"] = styled("context.warning", "metafun.environment.content.o.1"), ["4"] = styled("context.embedded", "metafun.environment.close.o.1"), ["5"] = styled("context.embedded", "metafun.environment.open.o.2"), ["6"] = styled("context.warning", "metafun.environment.content.o.2"), ["7"] = styled("context.embedded", "metafun.environment.close.o.2"), }, endCaptures = { ["0"] = styled("context.embedded", "metafun.environment.stop.o") }, }, metafun_environment_a = { ["begin"] = mpsenvironmentopen_a, ["end"] = mpsenvironmentclose_a, patterns = embedded("mps"), beginCaptures = { ["1"] = styled("context.embedded", "metafun.environment.start.a"), ["2"] = styled("context.embedded", "metafun.environment.open.a.1"), ["3"] = styled("context.warning", "metafun.environment.content.a.1"), ["4"] = styled("context.embedded", "metafun.environment.close.a.1"), ["5"] = styled("context.embedded", "metafun.environment.open.a.2"), ["6"] = styled("context.warning", "metafun.environment.content.a.2"), ["7"] = styled("context.embedded", "metafun.environment.close.a.2"), }, endCaptures = { ["0"] = styled("context.embedded", "metafun.environment.stop.a") }, }, metafun_command = { name = style("context.embedded", "metafun.command"), match = capturedmpscommands, }, }, patterns = { include("#comment"), include("#constant"), include("#lua_environment"), include("#lua_command"), include("#metafun_environment_o"), include("#metafun_environment_a"), include("#metafun_command"), include("#subsystem_prefix"), include("#subsystem_suffix"), include("#ifprimitive"), include("#helper"), include("#command"), include("#primitive"), include("#reserved"), include("#csname"), include("#escaped"), include("#grouping"), include("#special"), include("#extra"), }, } end -- The metafun lexer. do local metapostprimitives = { } local metapostinternals = { } local metapostshortcuts = { } local metapostcommands = { } local metafuninternals = { } local metafunshortcuts = { } local metafuncommands = { } local mergedshortcuts = { } local mergedinternals = { } do local definitions = loaddefinitions("scite-context-data-metapost.lua") if definitions then metapostprimitives = definitions.primitives or { } metapostinternals = definitions.internals or { } metapostshortcuts = definitions.shortcuts or { } metapostcommands = definitions.commands or { } end local definitions = loaddefinitions("scite-context-data-metafun.lua") if definitions then metafuninternals = definitions.internals or { } metafunshortcuts = definitions.shortcuts or { } metafuncommands = definitions.commands or { } end for i=1,#metapostshortcuts do mergedshortcuts[#mergedshortcuts+1] = metapostshortcuts[i] end for i=1,#metafunshortcuts do mergedshortcuts[#mergedshortcuts+1] = metafunshortcuts[i] end for i=1,#metapostinternals do mergedinternals[#mergedinternals+1] = metapostinternals[i] end for i=1,#metafuninternals do mergedinternals[#mergedinternals+1] = metafuninternals[i] end end local function words(list) table.sort(list,sorter) return "(" .. table.concat(list,"|") .. ")" .. "(?=[^a-zA-Z\\_@!?\127-\255])" end local capturedshortcuts = oneof(mergedshortcuts) local capturedinternals = words(mergedinternals) local capturedmetapostcommands = words(metapostcommands) local capturedmetafuncommands = words(metafuncommands) local capturedmetapostprimitives = words(metapostprimitives) local capturedsuffixes = oneof { "#@", "@#", "#" } local capturedspecials = oneof { "#@", "@#", "#", "(", ")", "[", "]", "{", "}", "<", ">", "=", ":", '"', } local capturedexatras = oneof { "+-+", "++", "~", "%", "^", "&", "_", "-", "+", "*", "/", "`", "'", "|", "\\", } local spaces = "\\s*" local mandatespaces = "\\s+" local identifier = "[a-zA-Z\\_@!?\127-\255]+" local decnumber = "[\\-]?[0-9]+(\\.[0-9]+)?([eE]\\-?[0-9]+)?" local comment = "%.*$\\n?" local stringopen = "\"" local stringclose = stringopen local qualifier = "[\\.]" local optionalqualifier = spaces .. qualifier .. spaces local capturedstringopen = capture(stringopen) local capturedstringclose = capture(stringclose) local capturedlua = capture("lua") local capturedopen = capture("\\(") local capturedclose = capture("\\)") local capturedtexopen = capture("(?:b|verbatim)tex") .. mandatespaces local capturedtexclose = mandatespaces .. capture("etex") local texcommand = "\\[a-zA-Z\\_@!?\127-\255]+" local style, styled = styler("mps") registerlexer { category = "mps", description = "ConTeXt MetaFun", suffixes = { "mp", "mpii", "mpiv", "mpvi" }, version = "1.0.0", setup = configuration { pairs = { { "{", "}" }, { "[", "]" }, { "(", ")" }, }, comments = { inline = "%", }, }, repository = { comment = { name = style("context.comment", "comment"), match = comment, }, internal = { name = style("context.reserved", "internal"), match = capturedshortcuts, }, shortcut = { name = style("context.data", "shortcut"), match = capturedinternals, }, helper = { name = style("context.command.metafun", "helper"), match = capturedmetafuncommands, }, plain = { name = style("context.plain", "plain"), match = capturedmetapostcommands, }, primitive = { name = style("context.primitive", "primitive"), match = capturedmetapostprimitives, }, quoted = { name = style("context.string", "string.text"), ["begin"] = stringopen, ["end"] = stringclose, beginCaptures = { ["0"] = styled("context.special", "string.open") }, endCaptures = { ["0"] = styled("context.special", "string.close") }, }, identifier = { name = style("context.default", "identifier"), match = identifier, }, suffix = { name = style("context.number", "suffix"), match = capturedsuffixes, }, special = { name = style("context.special", "special"), match = capturedspecials, }, number = { name = style("context.number", "number"), match = decnumber, }, extra = { name = "context.extra", match = capturedexatras, }, luacall = { ["begin"] = capturedlua .. spaces .. capturedopen .. spaces .. capturedstringopen, ["end"] = capturedstringclose .. spaces .. capturedclose, patterns = embedded("cld"), beginCaptures = { ["1"] = styled("context.embedded", "lua.command"), ["2"] = styled("context.special", "lua.open"), ["3"] = styled("context.special", "lua.text.open"), }, endCaptures = { ["1"] = styled("context.special", "lua.text.close"), ["2"] = styled("context.special", "lua.close"), }, }, -- default and embedded have the same color but differ in boldness luacall_suffixed = { name = style("context.embedded", "luacall"), ["begin"] = capturedlua, ["end"] = "(?!(" .. optionalqualifier .. identifier .. "))", patterns = { { match = qualifier, -- name = style("context.operator", "luacall.qualifier"), name = style("context.default", "luacall.qualifier"), }, } }, texlike = { -- simplified variant name = style("context.warning","unexpected.tex"), match = texcommand, }, texstuff = { name = style("context.string", "tex"), ["begin"] = capturedtexopen, ["end"] = capturedtexclose, patterns = embedded("tex"), beginCaptures = { ["1"] = styled("context.primitive", "tex.open") }, endCaptures = { ["1"] = styled("context.primitive", "tex.close") }, }, }, patterns = { include("#comment"), include("#internal"), include("#shortcut"), include("#luacall_suffixed"), include("#luacall"), include("#helper"), include("#plain"), include("#primitive"), include("#texstuff"), include("#suffix"), include("#identifier"), include("#number"), include("#quoted"), include("#special"), include("#texlike"), include("#extra"), }, } end -- The lua lexer. do local function words(list) table.sort(list,sorter) return "(" .. table.concat(list,"|") .. ")" .. "(?=[^a-zA-Z])" end local capturedkeywords = words { "and", "break", "do", "else", "elseif", "end", "false", "for", "function", -- "goto", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while", } local capturedbuiltin = words { "assert", "collectgarbage", "dofile", "error", "getmetatable", "ipairs", "load", "loadfile", "module", "next", "pairs", "pcall", "print", "rawequal", "rawget", "rawset", "require", "setmetatable", "tonumber", "tostring", "type", "unpack", "xpcall", "select", "string", "table", "coroutine", "debug", "file", "io", "lpeg", "math", "os", "package", "bit32", "utf8", -- todo: also extra luametatex ones } local capturedconstants = words { "_G", "_VERSION", "_M", "\\.\\.\\.", "_ENV", "__add", "__call", "__concat", "__div", "__idiv", "__eq", "__gc", "__index", "__le", "__lt", "__metatable", "__mode", "__mul", "__newindex", "__pow", "__sub", "__tostring", "__unm", "__len", "__pairs", "__ipairs", "__close", "NaN", "", "", } local capturedcsnames = words { -- todo: option "commands", "context", -- "ctxcmd", -- "ctx", "metafun", "metapost", "ctx[A-Za-z_]*", } local capturedoperators = oneof { "+", "-", "*", "/", "%", "^", "#", "=", "<", ">", ";", ":", ",", ".", "{", "}", "[", "]", "(", ")", "|", "~", "'" } local spaces = "\\s*" local identifier = "[_\\w][_\\w0-9]*" local qualifier = "[\\.\\:]" local optionalqualifier = spaces .. "[\\.\\:]*" .. spaces local doublequote = "\"" local singlequote = "\'" local doublecontent = "(?:\\\\\"|[^\"])*" local singlecontent = "(?:\\\\\'|[^\'])*" local captureddouble = capture(doublequote) .. capture(doublecontent) .. capture(doublequote) local capturedsingle = capture(singlequote) .. capture(singlecontent) .. capture(singlequote) local longcommentopen = "--\\[\\[" local longcommentclose = "\\]\\]" local longstringopen = "\\[(=*)\\[" local longstringclose = "\\](\\2)\\]" local shortcomment = "--.*$\\n?" local hexnumber = "[\\-]?0[xX][A-Fa-f0-9]+(\\.[A-Fa-f0-9]+)?([eEpP]\\-?[A-Fa-f0-9]+)?" local decnumber = "[\\-]?[0-9]+(\\.[0-9]+)?([eEpP]\\-?[0-9]+)?" local capturedidentifier = capture(identifier) local capturedgotodelimiter = capture("::") local capturedqualifier = capture(qualifier) local capturedgoto = capture("goto") local style, styled = styler("lua") local lualexer = { category = "lua", description = "ConTeXt Lua", -- suffixes = { "lua", "luc", "cld", "tuc", "luj", "lum", "tma", "lfg", "luv", "lui" }, version = "1.0.0", setup = configuration { pairs = { { "(", ")" }, { "{", "}" }, { "[", "]" }, }, comments = { inline = "--", display = { "--[[", "]]" }, }, }, repository = { shortcomment = { name = style("context.comment", "comment.short"), match = shortcomment, }, longcomment = { name = style("context.comment", "comment.long"), ["begin"] = longcommentopen, ["end"] = longcommentclose, }, keyword = { name = style("context.keyword", "reserved.keyword"), match = capturedkeywords, }, builtin = { name = style("context.plain", "reserved.builtin"), match = capturedbuiltin, }, constant = { name = style("context.data", "reserved.constants"), match = capturedconstants, }, csname = { name = style("context.user", "csname"), ["begin"] = capturedcsnames, ["end"] = "(?!(" .. optionalqualifier .. identifier .. "))", patterns = { { match = qualifier, name = style("context.operator", "csname.qualifier") }, } }, identifier_keyword = { match = spaces .. capturedqualifier .. spaces .. capturedkeywords, captures = { ["1"] = styled("context.operator", "identifier.keyword"), ["2"] = styled("context.warning", "identifier.keyword"), }, }, identifier_valid = { name = style("context.default", "identifier.valid"), match = identifier, }, ["goto"] = { match = capturedgoto .. spaces .. capturedidentifier, captures = { ["1"] = styled("context.keyword", "goto.keyword"), ["2"] = styled("context.grouping", "goto.target"), } }, label = { match = capturedgotodelimiter .. capturedidentifier .. capturedgotodelimiter, captures = { ["1"] = styled("context.keyword", "label.open"), ["2"] = styled("context.grouping", "label.target"), ["3"] = styled("context.keyword", "label.close"), } }, operator = { name = style("context.special", "operator"), match = capturedoperators, }, string_double = { match = captureddouble, captures = { ["1"] = styled("context.special", "doublequoted.open"), ["2"] = styled("context.string", "doublequoted.text"), ["3"] = styled("context.special", "doublequoted.close"), }, }, string_single = { match = capturedsingle, captures = { ["1"] = styled("context.special", "singlequoted.open"), ["2"] = styled("context.string", "singlequoted.text"), ["3"] = styled("context.special", "singlequoted.close"), }, }, string_long = { name = style("context.string", "long.text"), ["begin"] = longstringopen, ["end"] = longstringclose, beginCaptures = { ["0"] = styled("context.special", "string.long.open") }, endCaptures = { ["0"] = styled("context.special", "string.long.close") }, }, number_hex = { name = style("context.number", "hexnumber"), match = hexnumber, }, number = { name = style("context.number", "decnumber"), match = decnumber, }, }, patterns = { include("#keyword"), include("#buildin"), include("#constant"), include("#csname"), include("#goto"), include("#number_hex"), include("#number"), include("#identifier_keyword"), include("#identifier_valid"), include("#longcomment"), include("#string_long"), include("#string_double"), include("#string_single"), include("#shortcomment"), include("#label"), include("#operator"), }, } local texstringopen = "\\\\!!bs" local texstringclose = "\\\\!!es" local texcommand = "\\\\[A-Za-z\127-\255@\\!\\?_]*" local cldlexer = { category = "cld", description = "ConTeXt CLD", suffixes = { "lua", "luc", "cld", "tuc", "luj", "lum", "tma", "lfg", "luv", "lui" }, version = lualexer.version, setup = lualexer.setup, repository = { texstring = { name = style("context.string", "texstring.text"), ["begin"] = texstringopen, ["end"] = texstringclose, beginCaptures = { ["0"] = styled("context.special", "texstring.open") }, endCaptures = { ["0"] = styled("context.special", "texstring.close") }, }, -- texcomment = { -- -- maybe some day -- }, texcommand = { name = style("context.warning", "texcommand"), match = texcommand }, }, patterns = { include("#texstring"), -- include("#texcomment"), include("#texcommand"), }, } table.merge (cldlexer.repository,lualexer.repository) table.imerge(cldlexer.patterns, lualexer.patterns) registerlexer(lualexer) registerlexer(cldlexer) end -- The xml lexer. local xmllexer, xmlconfiguration do local spaces = "\\s*" local namespace = "(?:[-\\w.]+:)?" local name = "[-\\w.:]+" local equal = "=" local elementopen = "<" local elementclose = ">" local elementopenend = "]*)" local entity = "&.*?;" local doublequote = "\"" local singlequote = "\'" local doublecontent = "(?:\\\\\"|[^\"])*" local singlecontent = "(?:\\\\\'|[^\'])*" local captureddouble = capture(doublequote) .. capture(doublecontent) .. capture(doublequote) local capturedsingle = capture(singlequote) .. capture(singlecontent) .. capture(singlequote) local capturednamespace = capture(namespace) local capturedname = capture(name) local capturedopen = capture(elementopen) local capturedclose = capture(elementclose) local capturedempty = capture(elementempty) local capturedopenend = capture(elementopenend) local cdataopen = "" local commentopen = "" local processingopen = "<\\?" local processingclose = "\\?>" local instructionopen = processingopen .. name local instructionclose = processingclose local xmlopen = processingopen .. "xml" local xmlclose = processingclose local luaopen = processingopen .. "lua" local luaclose = processingclose local style, styled = styler("xml") registerlexer { category = "xml", description = "ConTeXt XML", suffixes = { "xml", "xsl", "xsd", "fo", "exa", "rlb", "rlg", "rlv", "rng", "xfdf", "xslt", "dtd", "lmx", "htm", "html", "xhtml", "ctx", "export", "svg", "xul", }, version = "1.0.0", setup = configuration { comments = { display = { "" }, }, }, repository = { attribute_double = { match = capturednamespace .. capturedname .. spaces .. equal .. spaces .. captureddouble, captures = { ["1"] = styled("context.plain", "attribute.double.namespace"), ["2"] = styled("context.constant", "attribute.double.name"), ["3"] = styled("context.special", "attribute.double.open"), ["4"] = styled("context.string", "attribute.double.text"), ["5"] = styled("context.special", "attribute.double.close"), }, }, attribute_single = { match = capturednamespace .. capturedname .. spaces .. equal .. spaces .. capturedsingle, captures = { ["1"] = styled("context.plain", "attribute.single.namespace"), ["2"] = styled("context.constant", "attribute.single.name"), ["3"] = styled("context.special", "attribute.single.open"), ["4"] = styled("context.string", "attribute.single.text"), ["5"] = styled("context.special", "attribute.single.close"), }, }, attributes = { patterns = { include("#attribute_double"), include("#attribute_single"), } }, entity = { name = style("context.constant", "entity"), match = entity, }, instruction = { name = style("context.default", "instruction.text"), ["begin"] = instructionopen, ["end"] = instructionclose, beginCaptures = { ["0"] = styled("context.command", "instruction.open") }, endCaptures = { ["0"] = styled("context.command", "instruction.close") }, }, instruction_xml = { ["begin"] = xmlopen, ["end"] = xmlclose, beginCaptures = { ["0"] = styled("context.command", "instruction.xml.open") }, endCaptures = { ["0"] = styled("context.command", "instruction.xml.close") }, patterns = { include("#attributes") } }, instruction_lua = { ["begin"] = luaopen, ["end"] = luaclose, patterns = embedded("cld"), beginCaptures = { ["0"] = styled("context.command", "instruction.lua.open") }, endCaptures = { ["0"] = styled("context.command", "instruction.lua.close") }, }, cdata = { name = style("context.default", "cdata.text"), ["begin"] = cdataopen, ["end"] = cdataclose, beginCaptures = { ["0"] = styled("context.command", "cdata.open") }, endCaptures = { ["0"] = styled("context.command", "cdata.close") }, }, comment = { name = style("context.comment", "comment.text"), ["begin"] = commentopen, ["end"] = commentclose, beginCaptures = { ["0"] = styled("context.command", "comment.open") }, endCaptures = { ["0"] = styled("context.command", "comment.close") }, }, open = { ["begin"] = capturedopen .. capturednamespace .. capturedname, ["end"] = capturedempty .. capturedclose, patterns = { include("#attributes") }, beginCaptures = { ["1"] = styled("context.keyword", "open.open"), ["2"] = styled("context.plain", "open.namespace"), ["3"] = styled("context.keyword", "open.name"), }, endCaptures = { ["1"] = styled("context.keyword", "open.empty"), ["2"] = styled("context.keyword", "open.close"), }, }, close = { match = capturedopenend .. capturednamespace .. capturedname .. spaces .. capturedclose, captures = { ["1"] = styled("context.keyword", "close.open"), ["2"] = styled("context.plain", "close.namespace"), ["3"] = styled("context.keyword", "close.name"), ["4"] = styled("context.keyword", "close.close"), }, }, element_error = { name = style("context.error","error"), match = elementopen .. elementnoclose .. elementclose, }, }, patterns = { -- include("#preamble"), include("#comment"), include("#cdata"), -- include("#doctype"), include("#instruction_xml"), include("#instruction_lua"), include("#instruction"), include("#close"), include("#open"), include("#element_error"), include("#entity"), }, } end -- The bibtex lexer. Again we assume the keys to be on the same line as the -- first snippet of the value. do local spaces = "\\s*" local open = "{" local close = "}" local hash = "#" local equal = "=" local comma = "," local doublequote = "\"" local doublecontent = "(?:\\\\\"|[^\"])*" local singlequote = "\'" local singlecontent = "(?:\\\\\'|[^\'])*" local groupopen = "{" local groupclose = "}" local groupcontent = "(?:\\\\{|\\\\}|[^\\{\\}])*" local shortcut = "@(?:string|String|STRING)" -- enforce consistency local comment = "@(?:comment|Comment|COMMENT)" -- enforce consistency local keyword = "[a-zA-Z0-9\\_@:\\-]+" local capturedcomment = spaces .. capture(comment) .. spaces local capturedshortcut = spaces .. capture(shortcut) .. spaces local capturedkeyword = spaces .. capture(keyword) .. spaces local capturedopen = spaces .. capture(open) .. spaces local capturedclose = spaces .. capture(close) .. spaces local capturedequal = spaces .. capture(equal) .. spaces local capturedcomma = spaces .. capture(comma) .. spaces local capturedhash = spaces .. capture(hash) .. spaces local captureddouble = spaces .. capture(doublequote) .. capture(doublecontent) .. capture(doublequote) .. spaces local capturedsingle = spaces .. capture(singlequote) .. capture(singlecontent) .. capture(singlequote) .. spaces local capturedgroup = spaces .. capture(groupopen) .. capture(groupcontent) .. capture(groupclose) .. spaces local forget = "%.*$\\n?" local style, styled = styler("bibtex") registerlexer { category = "bibtex", description = "ConTeXt bibTeX", suffixes = { "bib", "btx" }, version = "1.0.0", setup = configuration { pairs = { { "{", "}" }, }, comments = { inline = "%", }, }, repository = { forget = { name = style("context.comment", "comment.comment.inline"), match = forget, }, comment = { name = style("context.comment", "comment.comment.content"), ["begin"] = capturedcomment .. capturedopen, ["end"] = capturedclose, beginCaptures = { ["1"] = styled("context.keyword", "comment.name"), ["2"] = styled("context.grouping", "comment.open"), }, endCaptures = { ["1"] = styled("context.grouping", "comment.close"), }, }, -- a bit inefficient but good enough string_double = { match = capturedkeyword .. capturedequal .. captureddouble, captures = { ["1"] = styled("context.command","doublequoted.key"), ["2"] = styled("context.operator","doublequoted.equal"), ["3"] = styled("context.special", "doublequoted.open"), ["4"] = styled("context.text", "doublequoted.text"), ["5"] = styled("context.special", "doublequoted.close"), }, }, string_single = { match = capturedkeyword .. capturedequal .. capturedsingle, captures = { ["1"] = styled("context.command","singlequoted.key"), ["2"] = styled("context.operator","singlequoted.equal"), ["3"] = styled("context.special", "singlequoted.open"), ["4"] = styled("context.text", "singlequoted.text"), ["5"] = styled("context.special", "singlequoted.close"), }, }, string_grouped = { match = capturedkeyword .. capturedequal .. capturedgroup, captures = { ["1"] = styled("context.command","grouped.key"), ["2"] = styled("context.operator","grouped.equal"), ["3"] = styled("context.operator", "grouped.open"), ["4"] = styled("context.text", "grouped.text"), ["5"] = styled("context.operator", "grouped.close"), }, }, string_value = { match = capturedkeyword .. capturedequal .. capturedkeyword, captures = { ["1"] = styled("context.command", "value.key"), ["2"] = styled("context.operator", "value.equal"), ["3"] = styled("context.text", "value.text"), }, }, string_concat = { patterns = { { match = capturedhash .. captureddouble, captures = { ["1"] = styled("context.operator","concat.doublequoted.concatinator"), ["2"] = styled("context.special", "concat.doublequoted.open"), ["3"] = styled("context.text", "concat.doublequoted.text"), ["4"] = styled("context.special", "concat.doublequoted.close"), } }, { match = capturedhash .. capturedsingle, captures = { ["1"] = styled("context.operator","concat.singlequoted.concatinator"), ["2"] = styled("context.special", "concat.singlequoted.open"), ["3"] = styled("context.text", "concat.singlequoted.text"), ["4"] = styled("context.special", "concat.singlequoted.close"), }, }, { match = capturedhash .. capturedgroup, captures = { ["1"] = styled("context.operator","concat.grouped.concatinator"), ["2"] = styled("context.operator", "concat.grouped.open"), ["3"] = styled("context.text", "concat.grouped.text"), ["4"] = styled("context.operator", "concat.grouped.close"), }, }, { match = capturedhash .. capturedkeyword, captured = { ["1"] = styled("context.operator","concat.value.concatinator"), ["2"] = styled("context.text", "concat.value.text"), }, }, }, }, separator = { match = capturedcomma, name = style("context.operator","definition.separator"), }, definition = { name = style("context.warning","definition.error"), ["begin"] = capturedkeyword .. capturedopen .. capturedkeyword .. capturedcomma, ["end"] = capturedclose, beginCaptures = { ["1"] = styled("context.keyword", "definition.category"), ["2"] = styled("context.grouping", "definition.open"), ["3"] = styled("context.warning", "definition.label.text"), ["3"] = styled("context.operator", "definition.label.separator"), }, endCaptures = { ["1"] = styled("context.grouping", "definition.close"), }, patterns = { include("#string_double"), include("#string_single"), include("#string_grouped"), include("#string_value"), include("#string_concat"), include("#separator"), }, }, concatinator = { match = capturedhash, name = style("context.operator","definition.concatinator"), }, shortcut = { name = style("context.warning","shortcut.error"), ["begin"] = capturedshortcut .. capturedopen, ["end"] = capturedclose, beginCaptures = { ["1"] = styled("context.keyword", "shortcut.name"), ["2"] = styled("context.grouping", "shortcut.open"), }, endCaptures = { ["1"] = styled("context.grouping", "shortcut.close"), }, patterns = { include("#string_double"), include("#string_single"), include("#string_grouped"), include("#string_value"), include("#string_concat"), }, }, }, patterns = { include("#forget"), include("#comment"), include("#shortcut"), include("#definition"), }, } end -- The sql lexer (only needed occasionally in documentation and so). do -- ANSI SQL 92 | 99 | 2003 local function words(list) table.sort(list,sorter) local str = table.concat(list,"|") return "(" .. str .. "|" .. string.upper(str) .. ")" .. "(?=[^a-zA-Z])" end local capturedkeywords = words { "absolute", "action", "add", "after", "all", "allocate", "alter", "and", "any", "are", "array", "as", "asc", "asensitive", "assertion", "asymmetric", "at", "atomic", "authorization", "avg", "before", "begin", "between", "bigint", "binary", "bit", "bit_length", "blob", "boolean", "both", "breadth", "by", "call", "called", "cascade", "cascaded", "case", "cast", "catalog", "char", "char_length", "character", "character_length", "check", "clob", "close", "coalesce", "collate", "collation", "column", "commit", "condition", "connect", "connection", "constraint", "constraints", "constructor", "contains", "continue", "convert", "corresponding", "count", "create", "cross", "cube", "current", "current_date", "current_default_transform_group", "current_path", "current_role", "current_time", "current_timestamp", "current_transform_group_for_type", "current_user", "cursor", "cycle", "data", "date", "day", "deallocate", "dec", "decimal", "declare", "default", "deferrable", "deferred", "delete", "depth", "deref", "desc", "describe", "descriptor", "deterministic", "diagnostics", "disconnect", "distinct", "do", "domain", "double", "drop", "dynamic", "each", "element", "else", "elseif", "end", "equals", "escape", "except", "exception", "exec", "execute", "exists", "exit", "external", "extract", "false", "fetch", "filter", "first", "float", "for", "foreign", "found", "free", "from", "full", "function", "general", "get", "global", "go", "goto", "grant", "group", "grouping", "handler", "having", "hold", "hour", "identity", "if", "immediate", "in", "indicator", "initially", "inner", "inout", "input", "insensitive", "insert", "int", "integer", "intersect", "interval", "into", "is", "isolation", "iterate", "join", "key", "language", "large", "last", "lateral", "leading", "leave", "left", "level", "like", "local", "localtime", "localtimestamp", "locator", "loop", "lower", "map", "match", "max", "member", "merge", "method", "min", "minute", "modifies", "module", "month", "multiset", "names", "national", "natural", "nchar", "nclob", "new", "next", "no", "none", "not", "null", "nullif", "numeric", "object", "octet_length", "of", "old", "on", "only", "open", "option", "or", "order", "ordinality", "out", "outer", "output", "over", "overlaps", "pad", "parameter", "partial", "partition", "path", "position", "precision", "prepare", "preserve", "primary", "prior", "privileges", "procedure", "public", "range", "read", "reads", "real", "recursive", "ref", "references", "referencing", "relative", "release", "repeat", "resignal", "restrict", "result", "return", "returns", "revoke", "right", "role", "rollback", "rollup", "routine", "row", "rows", "savepoint", "schema", "scope", "scroll", "search", "second", "section", "select", "sensitive", "session", "session_user", "set", "sets", "signal", "similar", "size", "smallint", "some", "space", "specific", "specifictype", "sql", "sqlcode", "sqlerror", "sqlexception", "sqlstate", "sqlwarning", "start", "state", "static", "submultiset", "substring", "sum", "symmetric", "system", "system_user", "table", "tablesample", "temporary", "then", "time", "timestamp", "timezone_hour", "timezone_minute", "to", "trailing", "transaction", "translate", "translation", "treat", "trigger", "trim", "true", "under", "undo", "union", "unique", "unknown", "unnest", "until", "update", "upper", "usage", "user", "using", "value", "values", "varchar", "varying", "view", "when", "whenever", "where", "while", "window", "with", "within", "without", "work", "write", "year", "zone", } -- The dialects list is taken from drupal.org with standard subtracted. -- -- MySQL 3.23.x | 4.x | 5.x -- PostGreSQL 8.1 -- MS SQL Server 2000 -- MS ODBC -- Oracle 10.2 local captureddialects = words { "a", "abort", "abs", "access", "ada", "admin", "aggregate", "alias", "also", "always", "analyse", "analyze", "assignment", "attribute", "attributes", "audit", "auto_increment", "avg_row_length", "backup", "backward", "bernoulli", "bitvar", "bool", "break", "browse", "bulk", "c", "cache", "cardinality", "catalog_name", "ceil", "ceiling", "chain", "change", "character_set_catalog", "character_set_name", "character_set_schema", "characteristics", "characters", "checked", "checkpoint", "checksum", "class", "class_origin", "cluster", "clustered", "cobol", "collation_catalog", "collation_name", "collation_schema", "collect", "column_name", "columns", "command_function", "command_function_code", "comment", "committed", "completion", "compress", "compute", "condition_number", "connection_name", "constraint_catalog", "constraint_name", "constraint_schema", "containstable", "conversion", "copy", "corr", "covar_pop", "covar_samp", "createdb", "createrole", "createuser", "csv", "cume_dist", "cursor_name", "database", "databases", "datetime", "datetime_interval_code", "datetime_interval_precision", "day_hour", "day_microsecond", "day_minute", "day_second", "dayofmonth", "dayofweek", "dayofyear", "dbcc", "defaults", "defined", "definer", "degree", "delay_key_write", "delayed", "delimiter", "delimiters", "dense_rank", "deny", "derived", "destroy", "destructor", "dictionary", "disable", "disk", "dispatch", "distinctrow", "distributed", "div", "dual", "dummy", "dump", "dynamic_function", "dynamic_function_code", "enable", "enclosed", "encoding", "encrypted", "end-exec", "enum", "errlvl", "escaped", "every", "exclude", "excluding", "exclusive", "existing", "exp", "explain", "fields", "file", "fillfactor", "final", "float4", "float8", "floor", "flush", "following", "force", "fortran", "forward", "freetext", "freetexttable", "freeze", "fulltext", "fusion", "g", "generated", "granted", "grants", "greatest", "header", "heap", "hierarchy", "high_priority", "holdlock", "host", "hosts", "hour_microsecond", "hour_minute", "hour_second", "identified", "identity_insert", "identitycol", "ignore", "ilike", "immutable", "implementation", "implicit", "include", "including", "increment", "index", "infile", "infix", "inherit", "inherits", "initial", "initialize", "insert_id", "instance", "instantiable", "instead", "int1", "int2", "int3", "int4", "int8", "intersection", "invoker", "isam", "isnull", "k", "key_member", "key_type", "keys", "kill", "lancompiler", "last_insert_id", "least", "length", "less", "limit", "lineno", "lines", "listen", "ln", "load", "location", "lock", "login", "logs", "long", "longblob", "longtext", "low_priority", "m", "matched", "max_rows", "maxextents", "maxvalue", "mediumblob", "mediumint", "mediumtext", "message_length", "message_octet_length", "message_text", "middleint", "min_rows", "minus", "minute_microsecond", "minute_second", "minvalue", "mlslabel", "mod", "mode", "modify", "monthname", "more", "move", "mumps", "myisam", "name", "nesting", "no_write_to_binlog", "noaudit", "nocheck", "nocompress", "nocreatedb", "nocreaterole", "nocreateuser", "noinherit", "nologin", "nonclustered", "normalize", "normalized", "nosuperuser", "nothing", "notify", "notnull", "nowait", "nullable", "nulls", "number", "octets", "off", "offline", "offset", "offsets", "oids", "online", "opendatasource", "openquery", "openrowset", "openxml", "operation", "operator", "optimize", "optionally", "options", "ordering", "others", "outfile", "overlay", "overriding", "owner", "pack_keys", "parameter_mode", "parameter_name", "parameter_ordinal_position", "parameter_specific_catalog", "parameter_specific_name", "parameter_specific_schema", "parameters", "pascal", "password", "pctfree", "percent", "percent_rank", "percentile_cont", "percentile_disc", "placing", "plan", "pli", "postfix", "power", "preceding", "prefix", "preorder", "prepared", "print", "proc", "procedural", "process", "processlist", "purge", "quote", "raid0", "raiserror", "rank", "raw", "readtext", "recheck", "reconfigure", "regexp", "regr_avgx", "regr_avgy", "regr_count", "regr_intercept", "regr_r2", "regr_slope", "regr_sxx", "regr_sxy", "regr_syy", "reindex", "reload", "rename", "repeatable", "replace", "replication", "require", "reset", "resource", "restart", "restore", "returned_cardinality", "returned_length", "returned_octet_length", "returned_sqlstate", "rlike", "routine_catalog", "routine_name", "routine_schema", "row_count", "row_number", "rowcount", "rowguidcol", "rowid", "rownum", "rule", "save", "scale", "schema_name", "schemas", "scope_catalog", "scope_name", "scope_schema", "second_microsecond", "security", "self", "separator", "sequence", "serializable", "server_name", "setof", "setuser", "share", "show", "shutdown", "simple", "soname", "source", "spatial", "specific_name", "sql_big_result", "sql_big_selects", "sql_big_tables", "sql_calc_found_rows", "sql_log_off", "sql_log_update", "sql_low_priority_updates", "sql_select_limit", "sql_small_result", "sql_warnings", "sqlca", "sqrt", "ssl", "stable", "starting", "statement", "statistics", "status", "stddev_pop", "stddev_samp", "stdin", "stdout", "storage", "straight_join", "strict", "string", "structure", "style", "subclass_origin", "sublist", "successful", "superuser", "synonym", "sysdate", "sysid", "table_name", "tables", "tablespace", "temp", "template", "terminate", "terminated", "text", "textsize", "than", "ties", "tinyblob", "tinyint", "tinytext", "toast", "top", "top_level_count", "tran", "transaction_active", "transactions_committed", "transactions_rolled_back", "transform", "transforms", "trigger_catalog", "trigger_name", "trigger_schema", "truncate", "trusted", "tsequal", "type", "uescape", "uid", "unbounded", "uncommitted", "unencrypted", "unlisten", "unlock", "unnamed", "unsigned", "updatetext", "use", "user_defined_type_catalog", "user_defined_type_code", "user_defined_type_name", "user_defined_type_schema", "utc_date", "utc_time", "utc_timestamp", "vacuum", "valid", "validate", "validator", "var_pop", "var_samp", "varbinary", "varchar2", "varcharacter", "variable", "variables", "verbose", "volatile", "waitfor", "width_bucket", "writetext", "x509", "xor", "year_month", "zerofill", } local capturedoperators = oneof { "+", "-", "*", "/", "%", "^", "!", "&", "|", "?", "~", "=", "<", ">", ";", ":", ".", "{", "}", "[", "]", "(", ")", } local spaces = "\\s*" local identifier = "[a-zA-Z\\_][a-zA-Z0-9\\_]*" local comment = "%.*$\\n?" local commentopen = "/\\*" local commentclose = "\\*/" local doublequote = "\"" local singlequote = "\'" local reversequote = "`" local doublecontent = "(?:\\\\\"|[^\"])*" local singlecontent = "(?:\\\\\'|[^\'])*" local reversecontent = "(?:\\\\`|[^`])*" local decnumber = "[\\-]?[0-9]+(\\.[0-9]+)?([eEpP]\\-?[0-9]+)?" local captureddouble = capture(doublequote) .. capture(doublecontent) .. capture(doublequote) local capturedsingle = capture(singlequote) .. capture(singlecontent) .. capture(singlequote) local capturedreverse = capture(reversequote) .. capture(reversecontent) .. capture(reversequote) local style, styled = styler("sql") registerlexer { category = "sql", description = "ConTeXt SQL", suffixes = { "sql" }, version = "1.0.0", setup = configuration { -- comments = { -- inline = "...", -- display = { "...", "..." }, -- }, }, repository = { comment_short = { name = style("context.comment", "comment.comment"), match = comment, }, comment_long = { name = style("context.comment", "comment.text"), ["begin"] = commentopen, ["end"] = commentclose, beginCaptures = { ["0"] = styled("context.command", "comment.open") }, endCaptures = { ["0"] = styled("context.command", "comment.close") }, }, keyword_standard = { name = style("context.keyword", "reserved.standard"), match = capturedkeywords, }, keyword_dialect = { name = style("context.keyword", "reserved.dialect"), match = captureddialects, }, operator = { name = style("context.special", "operator"), match = capturedoperators, }, identifier = { name = style("context.text", "identifier"), match = identifier, }, string_double = { match = captureddouble, captures = { ["1"] = styled("context.special", "doublequoted.open"), ["2"] = styled("context.text", "doublequoted.text"), ["3"] = styled("context.special", "doublequoted.close"), }, }, string_single = { match = capturedsingle, captures = { ["1"] = styled("context.special", "singlequoted.open"), ["2"] = styled("context.text", "singlequoted.text"), ["3"] = styled("context.special", "singlequoted.close"), }, }, string_reverse = { match = capturedreverse, captures = { ["1"] = styled("context.special", "reversequoted.open"), ["2"] = styled("context.text", "reversequoted.text"), ["3"] = styled("context.special", "reversequoted.close"), }, }, number = { name = style("context.number", "number"), match = decnumber, }, }, patterns = { include("#keyword_standard"), include("#keyword_dialect"), include("#identifier"), include("#string_double"), include("#string_single"), include("#string_reverse"), include("#comment_long"), include("#comment_short"), include("#number"), include("#operator"), }, } end -- The bnf lexer (only used for documentation, untested). do local operators = oneof { "*", "+", "-", "/", ",", ".", ":", ";", "(", ")", "<", ">", "{", "}", "[", "]", "#", "=", "?", "@", "|", " ", "!","$", "%", "&", "\\", "^", "-", "_", "`", "~", } local spaces = "\\s*" local text = "[a-zA-Z0-9]|" .. operators local doublequote = "\"" local singlequote = "\'" local termopen = "<" local termclose = ">" local termcontent = "([a-zA-Z][a-zA-Z0-9\\-]*)" local becomes = "::=" local extra = "|" local captureddouble = capture(doublequote) .. capture(text) .. capture(doublequote) local capturedsingle = capture(singlequote) .. capture(text) .. capture(singlequote) local capturedterm = capture(termopen) .. capture(termcontent) .. capture(termclose) local style, styled = styler("bnf") registerlexer { category = "bnf", description = "ConTeXt BNF", suffixes = { "bnf" }, version = "1.0.0", setup = configuration { pairs = { { "<", ">" }, }, }, repository = { term = { match = capturedterm, captures = { ["1"] = styled("context.command", "term.open"), ["2"] = styled("context.text", "term.text"), ["3"] = styled("context.command", "term.close"), }, }, text_single = { match = capturedsingle, captures = { ["1"] = styled("context.special", "singlequoted.open"), ["2"] = styled("context.text", "singlequoted.text"), ["3"] = styled("context.special", "singlequoted.close"), }, }, text_double = { match = captureddouble, captures = { ["1"] = styled("context.special", "doublequoted.open"), ["2"] = styled("context.text", "doublequoted.text"), ["3"] = styled("context.special", "doublequoted.close"), }, }, becomes = { name = style("context.operator", "symbol.becomes"), match = becomes, }, extra = { name = style("context.extra", "symbol.extra"), match = extra, }, }, patterns = { include("#term"), include("#text_single"), include("#text_reverse"), include("#becomes"), include("#extra"), }, } end do -- A rather simple one, but consistent with the rest. I don't use an IDE or fancy -- features. No tricks for me. local function words(list) table.sort(list,sorter) return "\\b(" .. table.concat(list,"|") .. ")\\b" end local capturedkeywords = words { -- copied from cpp.lua -- c "asm", "auto", "break", "case", "const", "continue", "default", "do", "else", "extern", "false", "for", "goto", "if", "inline", "register", "return", "sizeof", "static", "switch", "true", "typedef", "volatile", "while", "restrict", -- hm "_Bool", "_Complex", "_Pragma", "_Imaginary", -- c++. "catch", "class", "const_cast", "delete", "dynamic_cast", "explicit", "export", "friend", "mutable", "namespace", "new", "operator", "private", "protected", "public", "signals", "slots", "reinterpret_cast", "static_assert", "static_cast", "template", "this", "throw", "try", "typeid", "typename", "using", "virtual" } local captureddatatypes = words { -- copied from cpp.lua "bool", "char", "double", "enum", "float", "int", "long", "short", "signed", "struct", "union", "unsigned", "void" } local capturedluatex = words { -- new "word", "halfword", "quarterword", "scaled", "pointer", "glueratio", } local capturedmacros = words { -- copied from cpp.lua "define", "elif", "else", "endif", "error", "if", "ifdef", "ifndef", "import", "include", "line", "pragma", "undef", "using", "warning" } local operators = oneof { "*", "+", "-", "/", "%", "^", "!", "&", "?", "~", "|", "=", "<", ">", ";", ":", ".", "{", "}", "[", "]", "(", ")", } local spaces = "\\s*" local identifier = "[A-Za-z_][A-Za-z_0-9]*" local comment = "//.*$\\n?" local commentopen = "/\\*" local commentclose = "\\*/" local doublequote = "\"" local singlequote = "\'" local reversequote = "`" local doublecontent = "(?:\\\\\"|[^\"])*" local singlecontent = "(?:\\\\\'|[^\'])*" local captureddouble = capture(doublequote) .. capture(doublecontent) .. capture(doublequote) local capturedsingle = capture(singlequote) .. capture(singlecontent) .. capture(singlequote) local texopen = "/\\*tex" local texclose = "\\*/" local hexnumber = "[\\-]?0[xX][A-Fa-f0-9]+(\\.[A-Fa-f0-9]+)?([eEpP]\\-?[A-Fa-f0-9]+)?" local decnumber = "[\\-]?[0-9]+(\\.[0-9]+)?([eEpP]\\-?[0-9]+)?" local capturedmacros = spaces .. capture("#") .. spaces .. capturedmacros local style, styled = styler("c") registerlexer { category = "cpp", description = "ConTeXt C", suffixes = { "c", "h", "cpp", "hpp" }, version = "1.0.0", setup = configuration { pairs = { { "{", "}" }, { "[", "]" }, { "(", ")" }, }, }, repository = { keyword = { match = capturedkeywords, name = style("context.keyword","c"), }, datatype = { match = captureddatatypes, name = style("context.keyword","datatype"), }, luatex = { match = capturedluatex, name = style("context.command","luatex"), }, macro = { match = capturedmacros, captures = { ["1"] = styled("context.data","macro.tag"), ["2"] = styled("context.data","macro.name"), } }, texcomment = { ["begin"] = texopen, ["end"] = texclose, patterns = embedded("tex"), beginCaptures = { ["0"] = styled("context.comment", "tex.open") }, endCaptures = { ["0"] = styled("context.comment", "tex.close") }, }, longcomment = { name = style("context.comment","long"), ["begin"] = commentopen, ["end"] = commentclose, }, shortcomment = { name = style("context.comment","short"), match = comment, }, identifier = { name = style("context.default","identifier"), match = identifier, }, operator = { name = style("context.operator","any"), match = operators, }, string_double = { match = captureddouble, captures = { ["1"] = styled("context.special", "doublequoted.open"), ["2"] = styled("context.string", "doublequoted.text"), ["3"] = styled("context.special", "doublequoted.close"), }, }, string_single = { match = capturedsingle, captures = { ["1"] = styled("context.special", "singlequoted.open"), ["2"] = styled("context.string", "singlequoted.text"), ["3"] = styled("context.special", "singlequoted.close"), }, }, hexnumber = { name = style("context.number","hex"), match = hexnumber, }, decnumber = { name = style("context.number","dec"), match = decnumber, }, }, patterns = { include("#keyword"), include("#datatype"), include("#luatex"), include("#identifier"), include("#macro"), include("#string_double"), include("#string_single"), include("#texcomment"), include("#longcomment"), include("#shortcomment"), include("#hexnumber"), include("#decnumber"), include("#operator"), }, } end -- The pdf lexer. do -- we can assume no errors in the syntax local spaces = "\\s*" local reserved = oneof { "true" ,"false" , "null" } local reference = "R" local dictionaryopen = "<<" local dictionaryclose = ">>" local arrayopen = "\\[" local arrayclose = "\\]" local stringopen = "\\(" local stringcontent = "(?:\\\\[\\(\\)]|[^\\(\\)])*" local stringclose = "\\)" local hexstringopen = "<" local hexstringcontent = "[^>]*" local hexstringclose = ">" local unicodebomb = "feff" local objectopen = "obj" -- maybe also ^ $ local objectclose = "endobj" -- maybe also ^ $ local streamopen = "^stream$" local streamclose = "^endstream$" local name = "/[^\\s<>/\\[\\]\\(\\)]+" -- no need to be more clever than this local integer = "[\\-]?[0-9]+" -- no need to be more clever than this local real = "[\\-]?[0-9]*[\\.]?[0-9]+" -- no need to be more clever than this local capturedcardinal = "([0-9]+)" local captureddictionaryopen = capture(dictionaryopen) local captureddictionaryclose = capture(dictionaryclose) local capturedarrayopen = capture(arrayopen) local capturedarrayclose = capture(arrayclose) local capturedobjectopen = capture(objectopen) local capturedobjectclose = capture(objectclose) local capturedname = capture(name) local capturedinteger = capture(integer) local capturedreal = capture(real) local capturedreserved = capture(reserved) local capturedreference = capture(reference) local capturedunicode = capture(hexstringopen) .. capture(unicodebomb) .. capture(hexstringcontent) .. capture(hexstringclose) local capturedunicode = capture(hexstringopen) .. capture(unicodebomb) .. capture(hexstringcontent) .. capture(hexstringclose) local capturedwhatsit = capture(hexstringopen) .. capture(hexstringcontent) .. capture(hexstringclose) local capturedstring = capture(stringopen) .. capture(stringcontent) .. capture(stringclose) local style, styled = styler("pdf") -- strings are not ok yet: there can be nested unescaped () but not critical now registerlexer { category = "pdf", description = "ConTeXt PDF", suffixes = { "pdf" }, version = "1.0.0", setup = configuration { pairs = { { "<", ">" }, { "[", "]" }, { "(", ")" }, }, }, repository = { comment = { name = style("context.comment","comment"), match = "%.*$\\n?", }, content = { patterns = { { include = "#dictionary" }, { include = "#stream" }, { include = "#array" }, { name = style("context.constant","object.content.name"), match = capturedname, }, { match = capturedcardinal .. spaces .. capturedcardinal .. spaces .. capturedreference, captures = { ["1"] = styled("context.warning","content.reference.1"), ["2"] = styled("context.warning","content.reference.2"), ["3"] = styled("context.command","content.reference.3"), } }, { name = style("context.number","content.real"), match = capturedreal, }, { name = style("context.number","content.integer"), match = capturedinteger, }, { match = capturedstring, captures = { ["1"] = styled("context.quote","content.string.open"), ["2"] = styled("context.string","content.string.text"), ["3"] = styled("context.quote","content.string.close"), } }, { name = style("context.number","content.reserved"), match = capturedreserved, }, { match = capturedunicode, captures = { ["1"] = styled("context.quote","content.unicode.open"), ["2"] = styled("context.plain","content.unicode.bomb"), ["3"] = styled("context.string","content.unicode.text"), ["4"] = styled("context.quote","content.unicode.close"), } }, { match = capturedwhatsit, captures = { ["1"] = styled("context.quote","content.whatsit.open"), ["2"] = styled("context.string","content.whatsit.text"), ["3"] = styled("context.quote","content.whatsit.close"), } }, }, }, object = { ["begin"] = capturedcardinal .. spaces .. capturedcardinal .. spaces .. capturedobjectopen, ["end"] = capturedobjectclose, patterns = { { include = "#content" } }, beginCaptures = { ["1"] = styled("context.warning","object.1"), ["2"] = styled("context.warning","object.2"), ["3"] = styled("context.keyword", "object.open") }, endCaptures = { ["1"] = styled("context.keyword", "object.close") }, }, array = { ["begin"] = capturedarrayopen, ["end"] = capturedarrayclose, patterns = { { include = "#content" } }, beginCaptures = { ["1"] = styled("context.grouping", "array.open") }, endCaptures = { ["1"] = styled("context.grouping", "array.close") }, }, dictionary = { ["begin"] = captureddictionaryopen, ["end"] = captureddictionaryclose, beginCaptures = { ["1"] = styled("context.grouping", "dictionary.open") }, endCaptures = { ["1"] = styled("context.grouping", "dictionary.close") }, patterns = { { ["begin"] = capturedname .. spaces, ["end"] = "(?=[>])", beginCaptures = { ["1"] = styled("context.command", "dictionary.name") }, patterns = { { include = "#content" } }, }, }, }, xref = { ["begin"] = "xref" .. spaces, ["end"] = "(?=[^0-9])", captures = { ["0"] = styled("context.keyword", "xref.1"), }, patterns = { { ["begin"] = capturedcardinal .. spaces .. capturedcardinal .. spaces, ["end"] = "(?=[^0-9])", captures = { ["1"] = styled("context.number", "xref.2"), ["2"] = styled("context.number", "xref.3"), }, patterns = { { ["begin"] = capturedcardinal .. spaces .. capturedcardinal .. spaces .. "([fn])" .. spaces, ["end"] = "(?=.)", captures = { ["1"] = styled("context.number", "xref.4"), ["2"] = styled("context.number", "xref.5"), ["3"] = styled("context.keyword", "xref.6"), }, }, }, }, }, }, startxref = { ["begin"] = "startxref" .. spaces, ["end"] = "(?=[^0-9])", captures = { ["0"] = styled("context.keyword", "startxref.1"), }, patterns = { { ["begin"] = capturedcardinal .. spaces, ["end"] = "(?=.)", captures = { ["1"] = styled("context.number", "startxref.2"), }, }, }, }, trailer = { name = style("context.keyword", "trailer"), match = "trailer", }, stream = { ["begin"] = streamopen, ["end"] = streamclose, beginCaptures = { ["0"] = styled("context.keyword", "stream.open") }, endCaptures = { ["0"] = styled("context.keyword", "stream.close") }, }, }, patterns = { include("#object"), include("#comment"), include("#trailer"), include("#dictionary"), -- cheat: trailer dict include("#startxref"), include("#xref"), }, } end -- The JSON lexer. I don't want to spend time on (and mess up the lexer) with -- some ugly multistage key/value parser so we just assume that the key is on -- the same line as the colon and the value. It looks bad otherwise anyway. do local spaces = "\\s*" local separator = "\\," local becomes = "\\:" local arrayopen = "\\[" local arrayclose = "\\]" local hashopen = "\\{" local hashclose = "\\}" local stringopen = "\"" local stringcontent = "(?:\\\\\"|[^\"])*" local stringclose = stringopen local reserved = oneof { "true", "false", "null" } local hexnumber = "[\\-]?0[xX][A-Fa-f0-9]+(\\.[A-Fa-f0-9]+)?([eEpP]\\-?[A-Fa-f0-9]+)?" local decnumber = "[\\-]?[0-9]+(\\.[0-9]+)?([eEpP]\\-?[0-9]+)?" local capturedarrayopen = capture(arrayopen) local capturedarrayclose = capture(arrayclose) local capturedhashopen = capture(hashopen) local capturedhashclose = capture(hashclose) local capturedreserved = capture(reserved) local capturedbecomes = capture(becomes) local capturedseparator = capture(separator) local capturedstring = capture(stringopen) .. capture(stringcontent) .. capture(stringclose) local capturedhexnumber = capture(hexnumber) local captureddecnumber = capture(decnumber) local style, styled = styler("json") registerlexer { category = "json", description = "ConTeXt JSON", suffixes = { "json" }, version = "1.0.0", setup = configuration { pairs = { { "{", "}" }, { "[", "]" }, }, }, repository = { separator = { name = style("context.operator","separator"), match = spaces .. capturedseparator, }, reserved = { name = style("context.primitive","reserved"), match = spaces .. capturedreserved, }, hexnumber = { name = style("context.number","hex"), match = spaces .. capturedhexnumber, }, decnumber = { name = style("context.number","dec"), match = spaces .. captureddecnumber, }, string = { match = spaces .. capturedstring, captures = { ["1"] = styled("context.quote","string.open"), ["2"] = styled("context.string","string.text"), ["3"] = styled("context.quote","string.close"), }, }, kv_reserved = { match = capturedstring .. spaces .. capturedbecomes .. spaces .. capturedreserved, captures = { ["1"] = styled("context.quote", "reserved.key.open"), ["2"] = styled("context.text", "reserved.key.text"), ["3"] = styled("context.quote", "reserved.key.close"), ["4"] = styled("context.operator", "reserved.becomes"), ["5"] = styled("context.primitive","reserved.value"), } }, kv_hexnumber = { match = capturedstring .. spaces .. capturedbecomes .. spaces .. capturedhexnumber, captures = { ["1"] = styled("context.quote", "hex.key.open"), ["2"] = styled("context.text", "hex.key.text"), ["3"] = styled("context.quote", "hex.key.close"), ["4"] = styled("context.operator","hex.becomes"), ["5"] = styled("context.number", "hex.value"), } }, kv_decnumber = { match = capturedstring .. spaces .. capturedbecomes .. spaces .. captureddecnumber, captures = { ["1"] = styled("context.quote", "dec.key.open"), ["2"] = styled("context.text", "dec.key.text"), ["3"] = styled("context.quote", "dec.key.close"), ["4"] = styled("context.operator","dec.becomes"), ["5"] = styled("context.number", "dec.value"), } }, kv_string = { match = capturedstring .. spaces .. capturedbecomes .. spaces .. capturedstring, captures = { ["1"] = styled("context.quote", "string.key.open"), ["2"] = styled("context.text", "string.key.text"), ["3"] = styled("context.quote", "string.key.close"), ["4"] = styled("context.operator","string.becomes"), ["5"] = styled("context.quote", "string.value.open"), ["6"] = styled("context.string", "string.value.text"), ["7"] = styled("context.quote", "string.value.close"), }, }, kv_array = { ["begin"] = capturedstring .. spaces .. capturedbecomes .. spaces .. capturedarrayopen, ["end"] = arrayclose, beginCaptures = { ["1"] = styled("context.quote", "array.key.open"), ["2"] = styled("context.text", "array.key.text"), ["3"] = styled("context.quote", "array.key.close"), ["4"] = styled("context.operator","array.becomes"), ["5"] = styled("context.grouping","array.value.open") }, endCaptures = { ["0"] = styled("context.grouping","array.value.close") }, patterns = { include("#content") }, }, kv_hash = { ["begin"] = capturedstring .. spaces .. capturedbecomes .. spaces .. capturedhashopen, ["end"] = hashclose, beginCaptures = { ["1"] = styled("context.quote", "hash.key.open"), ["2"] = styled("context.text", "hash.key.text"), ["3"] = styled("context.quote", "hash.key.close"), ["4"] = styled("context.operator","hash.becomes"), ["5"] = styled("context.grouping","hash.value.open") }, endCaptures = { ["0"] = styled("context.grouping","hash.value.close") }, patterns = { include("#kv_content") }, }, content = { patterns = { include("#string"), include("#hexnumber"), include("#decnumber"), include("#reserved"), include("#hash"), include("#array"), include("#separator"), }, }, kv_content = { patterns = { include("#kv_string"), include("#kv_hexnumber"), include("#kv_decnumber"), include("#kv_reserved"), include("#kv_hash"), include("#kv_array"), include("#separator"), }, }, array = { ["begin"] = arrayopen, ["end"] = arrayclose, beginCaptures = { ["0"] = styled("context.grouping","array.open") }, endCaptures = { ["0"] = styled("context.grouping","array.close") }, patterns = { include("#content") }, }, hash = { ["begin"] = hashopen, ["end"] = hashclose, beginCaptures = { ["0"] = styled("context.grouping","hash.open") }, endCaptures = { ["0"] = styled("context.grouping","hash.close") }, patterns = { include("#kv_content") }, }, }, patterns = { include("#content"), }, } end savepackage() end function scripts.vscode.start() local path = locate() if path then local command = 'start "vs code context" code --reuse-window --ignore-gpu-blacklist --extensions-dir "' .. path .. '" --install-extension context' report("running command: %s",command) os.execute(command) end end if environment.arguments.generate then scripts.vscode.generate() elseif environment.arguments.start then scripts.vscode.start() elseif environment.arguments.exporthelp then application.export(environment.arguments.exporthelp,environment.files[1]) else application.help() end scripts.vscode.generate([[t:/vscode/data/context/extensions]])