5

I have followed the wiki to write a custom pretty printer, pret-ada.lua. I placed it next to my tex file.

The wiki says that I have to use \installprettytype to register it. However, it yields Undefined control sequence. Some digging revealed a mailing list post which explains that it has been removed in MkIV. But it does not explain how I register my pretty printer with ConTeXt now.

So, how can I make ConTeXt use my pretty printer? Just removing the command leads to no pretty printing at all:

%\installprettytype[ADA][ADA] % Undefined control sequence!
\definetyping[Ada][option=ADA]

\starttext
  \startAda
    A := "String";
  \stopAda
\stoptext

Edit

Here's what I have come up with so far for the lexer. It is most probably horribly wrong because I could not test it yet. I copied parts of it from pret-c.lua.

local keywords = {
  "abort", "abs", "abstract", "accept", "access", "aliased", "all", "and",
  "array", "at", "begin", "body", "case", "constant", "declare", "delay",
  "delta", "digits", "do", "else", "elsif", "end", "entry", "exception",
  "exit", "for", "function", "generic", "goto", "if", "in", "interface", "is",
  "limited", "loop", "mod", "new", "not", "null", "of", "or", "others", "out",
  "overriding", "package", "pragma", "private", "procedure", "protected",
  "raise", "range", "record", "rem", "renames", "requeue", "return", "reverse",
  "select", "separate", "some", "subtype", "synchronized", "tagged", "task",
  "terminate", "then", "type", "until", "use", "when", "while", "with", "xor"
}

local keyword_colors = {}
for _, n in ipairs(keywords) do
  keyword_colors[n] = "keyword"
end

local colors = {
  {name = "comment", color="gray"},
  {name = "keyword", color="blue"},
  {name = "string", color="green"}
}
local color

local function init()
  color = 0
  local def_colors = ""
  local palet = "\\definepalet[Ccolorpretty]["
  for _, c in ipairs(colors) do
    def_colors = format("%s\\doifcolorelese{C%s}{}{\\definecolor[C%s][%s]}",
        def_colors, c.name, c.name, c.color)
    palet = format("%s%s=C%s,", palet, c.name, c.name)
  end
  palet = palet:gsub("(.+),$", "%1]")
  texsprint(def_colors)
  texsprint(palet)
  buffers.currentcolors = {}
  for i, c in ipairs(colors) do
    buffers.currentcolors[i] = c.name
  end
end

local function finish_color()
  color = buffers.finishstate(color)
end

local function change_color(n)
  color = buffers.changestate(color_by_name[n], color)
end

local visualizer = buffers.newvisualizer('ada')

visualizer.begin_of_display = init
visualizer.begin_of_inline = init
visualizer.end_of_display = finish_color
visualizer.end_of_inline = finish_color

local function next_token(lexer)
  local buf = ""
  if lexer.c == " " or lexer.c == "\t" then
    buf = lexer.c
    lexer.c = lexer.next()
    while lexer.c == " " or lexer.c == "\t" do
      buf = buf .. lexer.c
      lexer.c = lexer.next()
    end
  elseif lexer.c = "\"" then
    while true do
      lexer.c = lexer.next()
      if lexer.c == nil then break end
      buf = buf .. lexer.c
      if lexer.c == "\"" then break end
    end
  elseif lexer.c == "-" then
    buf = buf .. lexer.c
    lexer.c = lexer.next()
    if lexer.c == "-" then
      while lexer.c ~= nil do
        buf = buf .. lexer.c
        lexer.c = lexer.next()
      end
    end
  elseif lexer.c:match("[%w_]") then
    while lexer.c != nil and lexer.c:match("[%w_]") do
      buf = buf .. lexer.c
      lexer.c = lexer.next()
    end
  else
    buf = lexer.c
    lexer.c = lexer.next()
  end
  return buf
end

function string.starts(String,Start)
  return string.sub(String,1,string.len(Start))==Start
end

function visualizer.flush_line(str, nested)
  local lexer = {
    next = utfcharacters(str)
  }
  lexer.c = lexer.next()
  while lexer.c ~= nil do
    local token = next_token(lexer)
    if token:starts("--") then
      change_color("comment")
      texsprint(token)
      finish_color()
    elseif token:starts("\"") then
      change_color("string")
      texsprint(token)
      finish_color()
    elseif keyword_colors[token] then
      change_color("keyword")
      texsprint(token)
      finish_color()
    else
      texsprint(token)
    end
  end
end
Henri Menke
  • 109,596
flyx
  • 2,051

2 Answers2

4

An alternative option is to use the t-vim module which uses vim editor for syntax highlighting. It is slower than using a lua based lexer, but the results are cached, so there is very little speed penalty in the long run. The advantage is that you get support for all languages supported by vim.

Here is how you could define an Ada syntax highlighting evironment:

\usemodule[vim]
\definevimtyping[Ada][syntax=ADA]

\starttext
  \startAda
    A := "String";
  \stopAda
\stoptext

which gives

enter image description here

Aditya
  • 62,301
  • I am aware of this option, but I imagine that this would be difficult to get to run under Windows. Also, I want to have the lexer customizable in the long run (e.g. for highlighting parts of the code). – flyx Oct 11 '16 at 07:18
  • @flyx: Although I don't run windows myself, I had tested the module on windows when it was released initially and it works. There are other users who run it on windows. So, give it a shot and let me know if it does not work. – Aditya Oct 11 '16 at 16:11
  • Could you elaborate on what you mean by "highlighting parts of the code". – Aditya Oct 11 '16 at 16:12
  • This leads too far away from the original question. I'll just go with Henri's solution. – flyx Oct 11 '16 at 18:41
3

The syntax you are using seems to be very old. The module you are referring to was last updated in 2010 and also the wiki page was last touched in 2010. I did not find any mention of the functions you used in the current source tree. Probably, this method is just deprecated.

By now all lexers and parser in ConTeXt use LPEG. I copy-pasted the Lua lexer to adapt it to ADA. Since I don't speak ADA, I cannot say whether the highlighting is correct or not. Also, I'm not an LPEG wizard, so parsing might also be awkward.

buff-imp-ada.mkiv

\registerctxluafile{buff-imp-ada.lua}{1.001}

\unprotect

\definestartstop
    [AdaSnippet]
    [DefaultSnippet]

\definestartstop
    [AdaSnippetName]
    [\c!color=,
     \c!style=boldface]

\definestartstop
    [AdaSnippetNameKeyword]
    [\c!color=darkgreen,
     \c!style=boldface]

\definestartstop
    [AdaSnippetBoundary]
    [\c!color=darkblue,
     \c!style=boldface]

\definestartstop
    [AdaSnippetString]
    [AdaSnippet]

\definestartstop
    [AdaSnippetQuote]
    [AdaSnippetBoundary]

\definestartstop
    [AdaSnippetSpecial]
    [\c!color=darkred,
     \c!style=boldface]

\definestartstop
    [AdaSnippetComment]
    [\c!color=darkyellow,
     \c!style=boldface]

\definetyping
    [ADA]
    [\c!option=ada]

\protect \endinput

buff-imp-ada.lua

local format, tohash = string.format, table.tohash
local P, S, V, patterns = lpeg.P, lpeg.S, lpeg.V, lpeg.patterns

local context                 = context
local verbatim                = context.verbatim
local makepattern             = visualizers.makepattern

local AdaSnippet              = context.AdaSnippet
local startAdaSnippet         = context.startAdaSnippet
local stopAdaSnippet          = context.stopAdaSnippet

local AdaSnippetBoundary      = verbatim.AdaSnippetBoundary
local AdaSnippetQuote         = verbatim.AdaSnippetQuote
local AdaSnippetString        = verbatim.AdaSnippetString
local AdaSnippetSpecial       = verbatim.AdaSnippetSpecial
local AdaSnippetComment       = verbatim.AdaSnippetComment
local AdaSnippetNameKeyword   = verbatim.AdaSnippetNameKeyword
local AdaSnippetName          = verbatim.AdaSnippetName

local keywords = tohash {
   "abort", "abs", "abstract", "accept", "access", "aliased", "all", "and",
   "array", "at", "begin", "body", "case", "constant", "declare", "delay",
   "delta", "digits", "do", "else", "elsif", "end", "entry", "exception",
   "exit", "for", "function", "generic", "goto", "if", "in", "interface", "is",
   "limited", "loop", "mod", "new", "not", "null", "of", "or", "others", "out",
   "overriding", "package", "pragma", "private", "procedure", "protected",
   "raise", "range", "record", "rem", "renames", "requeue", "return", "reverse",
   "select", "separate", "some", "subtype", "synchronized", "tagged", "task",
   "terminate", "then", "type", "until", "use", "when", "while", "with", "xor"
}

local function visualizename(s)
    if keywords[s] then
        AdaSnippetNameKeyword(s)
    else
        AdaSnippetName(s)
    end
end

local handler = visualizers.newhandler {
    startinline  = function() AdaSnippet(false,"{") end,
    stopinline   = function() context("}") end,

    startdisplay = function() startAdaSnippet() end,
    stopdisplay  = function() stopAdaSnippet() end ,

    boundary     = function(s) AdaSnippetBoundary(s) end,
    special      = function(s) AdaSnippetSpecial(s) end,
    comment      = function(s) AdaSnippetComment(s) end,
    quote        = function(s) AdaSnippetQuote(s) end,
    string       = function(s) AdaSnippetString(s) end,

    name         = visualizename,
}

local comment     = P("--")
local name        = (patterns.letter + S("_"))^1
local boundary    = S('()[]:=<>;"')
local special     = S("-+/*|`!?^&%.,")

local grammar = visualizers.newgrammar("default", { "visualizer",

    comment     = makepattern(handler,"comment",comment)
                * (V("space") + V("content"))^0,
    dstring     = makepattern(handler,"quote",patterns.dquote)
                * makepattern(handler,"string",patterns.nodquote)
                * makepattern(handler,"quote",patterns.dquote),
    name        = makepattern(handler,"name",name),
    boundary    = makepattern(handler,"boundary",boundary),
    special     = makepattern(handler,"special",special),

    pattern     =
        V("comment") + V("dstring") + V("name") + V("boundary") + V("special")
      + V("newline") * V("emptyline")^0 * V("beginline")
      + V("space")
      + V("default"),

    visualizer  =
        V("pattern")^1

} )

local parser = P(grammar)

visualizers.register("ada", { parser = parser, handler = handler, grammar = grammar } )

Test

\loadmarkfile{buff-imp-ada}

\starttext
  \startADA
    with Ada.Text_IO; use Ada.Text_IO;
    procedure Hello is
    begin
      Put_Line ("Hello, world!");
    end Hello;
  \stopADA
\stoptext

enter image description here

Henri Menke
  • 109,596