if not modules then modules = { } end modules ['trac-lmx'] = {
version = 1.002,
comment = "companion to trac-lmx.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
}
-- this one will be adpated to the latest helpers
local type, tostring, rawget, loadstring, pcall = type, tostring, rawget, loadstring, pcall
local format, sub, gsub = string.format, string.sub, string.gsub
local concat = table.concat
local collapsespaces = string.collapsespaces
local P, Cc, Cs, C, Carg, lpegmatch = lpeg.P, lpeg.Cc, lpeg.Cs, lpeg.C, lpeg.Carg, lpeg.match
local joinpath, replacesuffix, pathpart, filesuffix = file.join, file.replacesuffix, file.pathpart, file.suffix
local allocate = utilities.storage.allocate
local setmetatableindex = table.setmetatableindex
----- trace_templates = false trackers .register("lmx.templates", function(v) trace_templates = v end)
local trace_variables = false trackers .register("lmx.variables", function(v) trace_variables = v end)
local cache_templates = true directives.register("lmx.cache.templates",function(v) cache_templates = v end)
local cache_files = true directives.register("lmx.cache.files", function(v) cache_files = v end)
local report_lmx = logs.reporter("lmx")
local report_error = logs.reporter("lmx","error")
lmx = lmx or { }
local lmx = lmx
-- This will change: we will just pass the global defaults as argument, but then we need
-- to rewrite some older code or come up with an ugly trick.
local lmxvariables = {
['title-default'] = 'ConTeXt LMX File',
['color-background-green'] = '#4F6F6F',
['color-background-blue'] = '#6F6F8F',
['color-background-yellow'] = '#8F8F6F',
['color-background-purple'] = '#8F6F8F',
['color-background-body'] = '#808080',
['color-background-main'] = '#3F3F3F',
}
local lmxinherited = {
['title'] = 'title-default',
['color-background-one'] = 'color-background-green',
['color-background-two'] = 'color-background-blue',
['color-background-three'] = 'color-background-one',
['color-background-four'] = 'color-background-two',
}
lmx.variables = lmxvariables
lmx.inherited = lmxinherited
setmetatableindex(lmxvariables,function(t,k)
k = lmxinherited[k]
while k do
local v = rawget(lmxvariables,k)
if v then
return v
end
k = lmxinherited[k]
end
end)
function lmx.set(key,value)
lmxvariables[key] = value
end
function lmx.get(key)
return lmxvariables[key] or ""
end
lmx.report = report_lmx
-- helpers
-- the variables table is an empty one that gets linked to a defaults table
-- that gets passed with a creation (first time only) and that itself links
-- to one that gets passed to the converter
local variables = { } -- we assume no nesting
local result = { } -- we assume no nesting
local function do_print(one,two,...)
if two then
result[#result+1] = concat { one, two, ... }
else
result[#result+1] = one
end
end
-- Although it does not make much sense for most elements, we provide a mechanism
-- to print wrapped content, something that is more efficient when we are constructing
-- tables.
local html = { }
lmx.html = html
function html.td(str)
if type(str) == "table" then
for i=1,#str do -- spoils t !
str[i] = format("
%s | ",str[i] or "")
end
result[#result+1] = concat(str)
else
result[#result+1] = format("%s | ",str or "")
end
end
function html.th(str)
if type(str) == "table" then
for i=1,#str do -- spoils t !
str[i] = format("%s | ",str[i])
end
result[#result+1] = concat(str)
else
result[#result+1] = format("%s | ",str or "")
end
end
function html.a(text,url)
result[#result+1] = format("%s",url,text)
end
setmetatableindex(html,function(t,k)
local f = format("<%s>%%s%s>",k,k)
local v = function(str) result[#result+1] = format(f,str or "") end
t[k] = v
return v
end)
-- Loading templates:
local function loadedfile(name)
name = resolvers and resolvers.findfile and resolvers.findfile(name) or name
local data = io.loaddata(name)
if not data or data == "" then
report_lmx("file %a is empty",name)
end
return data
end
local function loadedsubfile(name)
return io.loaddata(resolvers and resolvers.findfile and resolvers.findfile(name) or name)
end
lmx.loadedfile = loadedfile
-- A few helpers (the next one could end up in l-lpeg):
local usedpaths = { }
local givenpath = nil
local do_nested_include = nil
local pattern = lpeg.replacer {
["&"] = "&",
[">"] = ">",
["<"] = "<",
['"'] = """,
}
local function do_escape(str)
return lpegmatch(pattern,str) or str
end
local function do_variable(str)
local value = variables[str]
if not trace_variables then
-- nothing
elseif type(value) == "string" then
if #value > 80 then
report_lmx("variable %a is set to: %s ...",str,collapsespaces(sub(value,1,80)))
else
report_lmx("variable %a is set to: %s",str,collapsespaces(value))
end
elseif type(value) == "nil" then
report_lmx("variable %a is set to: %s",str,"")
else
report_lmx("variable %a is set to: %S",str,value)
end
if type(value) == "function" then -- obsolete ... will go away
return value(str)
else
return value
end
end
local function do_type(str)
if str and str ~= "" then
result[#result+1] = format("%s",do_escape(str))
end
end
local function do_fprint(str,...)
if str and str ~= "" then
result[#result+1] = format(str,...)
end
end
local function do_eprint(str,...)
if str and str ~= "" then
result[#result+1] = lpegmatch(pattern,format(str,...))
end
end
local function do_print_variable(str)
local str = do_variable(str) -- variables[str]
if str and str ~= "" then
result[#result+1] = str
end
end
local function do_type_variable(str)
local str = do_variable(str) -- variables[str]
if str and str ~= "" then
result[#result+1] = format("%s",do_escape(str))
end
end
local function do_include(filename,option)
local data = loadedsubfile(filename)
if (not data or data == "") and givenpath then
data = loadedsubfile(joinpath(givenpath,filename))
end
if (not data or data == "") and type(usedpaths) == "table" then
for i=1,#usedpaths do
data = loadedsubfile(joinpath(usedpaths[i],filename))
if data and data ~= "" then
break
end
end
end
if not data or data == "" then
data = format("",filename)
report_lmx("include file %a is empty",filename)
else
-- report_lmx("included file: %s",filename)
data = do_nested_include(data)
end
if filesuffix(filename,"css") and option == "strip" then -- new
data = lmx.stripcss(data)
end
return data
end
-- Flushers:
lmx.print = do_print
lmx.type = do_type
lmx.eprint = do_eprint
lmx.fprint = do_fprint
lmx.escape = do_escape
lmx.urlescape = url.escape
lmx.variable = do_variable
lmx.include = do_include
lmx.inject = do_print
lmx.finject = do_fprint
lmx.einject = do_eprint
lmx.pv = do_print_variable
lmx.tv = do_type_variable
-- The next functions set up the closure.
function lmx.initialize(d,v)
if not v then
setmetatableindex(d,lmxvariables)
if variables ~= d then
setmetatableindex(variables,d)
if trace_variables then
report_lmx("using chain: variables => given defaults => lmx variables")
end
elseif trace_variables then
report_lmx("using chain: variables == given defaults => lmx variables")
end
elseif d ~= v then
setmetatableindex(v,d)
if d ~= lmxvariables then
setmetatableindex(d,lmxvariables)
if variables ~= v then
setmetatableindex(variables,v)
if trace_variables then
report_lmx("using chain: variables => given variables => given defaults => lmx variables")
end
elseif trace_variables then
report_lmx("using chain: variables == given variables => given defaults => lmx variables")
end
else
if variables ~= v then
setmetatableindex(variables,v)
if trace_variables then
report_lmx("using chain: variabes => given variables => given defaults")
end
elseif trace_variables then
report_lmx("using chain: variables == given variables => given defaults")
end
end
else
setmetatableindex(v,lmxvariables)
if variables ~= v then
setmetatableindex(variables,v)
if trace_variables then
report_lmx("using chain: variables => given variables => lmx variables")
end
elseif trace_variables then
report_lmx("using chain: variables == given variables => lmx variables")
end
end
result = { }
end
function lmx.finalized()
local collapsed = concat(result)
result = { } -- free memory
return collapsed
end
function lmx.getvariables()
return variables
end
function lmx.reset()
-- obsolete
end
-- Creation: (todo: strip )
-- local template = [[
-- return function(defaults,variables)
--
-- -- initialize
--
-- lmx.initialize(defaults,variables)
--
-- -- interface
--
-- local definitions = { }
-- local variables = lmx.getvariables()
-- local html = lmx.html
-- local inject = lmx.print
-- local finject = lmx.fprint
-- local einject = lmx.eprint
-- local escape = lmx.escape
-- local verbose = lmx.type
--
-- -- shortcuts (sort of obsolete as there is no gain)
--
-- local p = lmx.print
-- local f = lmx.fprint
-- local v = lmx.variable
-- local e = lmx.escape
-- local t = lmx.type
-- local pv = lmx.pv
-- local tv = lmx.tv
--
-- -- generator
--
-- %s
--
-- -- finalize
--
-- return lmx.finalized()
--
-- end
-- ]]
local template = [[
-- interface
local html = lmx.html
local inject = lmx.print
local finject = lmx.fprint -- better use the following
local einject = lmx.eprint -- better use the following
local injectf = lmx.fprint
local injecte = lmx.eprint
local injectfmt = lmx.fprint
local injectesc = lmx.eprint
local escape = lmx.escape
local verbose = lmx.type
local i_n_j_e_c_t = lmx.print
-- shortcuts (sort of obsolete as there is no gain)
local p = lmx.print
local f = lmx.fprint
local v = lmx.variable
local e = lmx.escape
local t = lmx.type
local pv = lmx.pv
local tv = lmx.tv
local lmx_initialize = lmx.initialize
local lmx_finalized = lmx.finalized
local lmx_getvariables = lmx.getvariables
-- generator
return function(defaults,variables)
lmx_initialize(defaults,variables)
local definitions = { }
local variables = lmx_getvariables()
%s -- the action: appends to result
return lmx_finalized()
end
]]
local function savedefinition(definitions,tag,content)
definitions[tag] = content
return ""
end
local function getdefinition(definitions,tag)
return definitions[tag] or ""
end
local whitespace = lpeg.patterns.whitespace
local optionalspaces = whitespace^0
local dquote = P('"')
local begincomment = P("")
local beginembedxml = P("")
local endembedxml = P("?>")
local beginembedcss = P("/*")
local endembedcss = P("*/")
local gobbledendxml = (optionalspaces * endembedxml) / ""
----- argumentxml = (1-gobbledendxml)^0
local argumentxml = (whitespace^1 + dquote * C((1-dquote)^1) * dquote + C((1-gobbledendxml-whitespace)^1))^0
local gobbledendcss = (optionalspaces * endembedcss) / ""
----- argumentcss = (1-gobbledendcss)^0
local argumentcss = (whitespace^1 + dquote * C((1-dquote)^1) * dquote + C((1-gobbledendcss-whitespace)^1))^0
local commentxml = (begincomment * (1-endcomment)^0 * endcomment) / ""
local beginluaxml = (beginembedxml * P("lua")) / ""
local endluaxml = endembedxml / ""
local luacodexml = beginluaxml
* (1-endluaxml)^1
* endluaxml
local beginluacss = (beginembedcss * P("lua")) / ""
local endluacss = endembedcss / ""
local luacodecss = beginluacss
* (1-endluacss)^1
* endluacss
local othercode = (1-beginluaxml-beginluacss)^1 / " i_n_j_e_c_t[==[%0]==] "
local includexml = ((beginembedxml * P("lmx-include") * optionalspaces) / "")
* (argumentxml / do_include)
* gobbledendxml
local includecss = ((beginembedcss * P("lmx-include") * optionalspaces) / "")
* (argumentcss / do_include)
* gobbledendcss
local definexml_b = ((beginembedxml * P("lmx-define-begin") * optionalspaces) / "")
* argumentxml
* gobbledendxml
local definexml_e = ((beginembedxml * P("lmx-define-end") * optionalspaces) / "")
* argumentxml
* gobbledendxml
local definexml_c = C((1-definexml_e)^0)
local definexml = (Carg(1) * C(definexml_b) * definexml_c * definexml_e) / savedefinition
local resolvexml = ((beginembedxml * P("lmx-resolve") * optionalspaces) / "")
* ((Carg(1) * C(argumentxml)) / getdefinition)
* gobbledendxml
local definecss_b = ((beginembedcss * P("lmx-define-begin") * optionalspaces) / "")
* argumentcss
* gobbledendcss
local definecss_e = ((beginembedcss * P("lmx-define-end") * optionalspaces) / "")
* argumentcss
* gobbledendcss
local definecss_c = C((1-definecss_e)^0)
local definecss = (Carg(1) * C(definecss_b) * definecss_c * definecss_e) / savedefinition
local resolvecss = ((beginembedcss * P("lmx-resolve") * optionalspaces) / "")
* ((Carg(1) * C(argumentcss)) / getdefinition)
* gobbledendcss
----- pattern_1 = Cs((commentxml + includexml + includecss + P(1))^0) -- get rid of xml comments asap .. not good enough: embedded css and script is in