#!/usr/bin/env texlua -------------------------------------------------------------------------------- -- FILE: rst_directives.lua -- USAGE: called by rst_parser.lua -- DESCRIPTION: Complement to the reStructuredText parser -- AUTHOR: Philipp Gesang (Phg), -- CHANGED: 2012-06-05 22:17:51+0200 -------------------------------------------------------------------------------- -- local helpers = helpers or thirddata and thirddata.rst_helpers -------------------------------------------------------------------------------- -- Directives for use with |substitutions| -------------------------------------------------------------------------------- local rst_directives = { } thirddata.rst_directives = rst_directives local rst_context = thirddata.rst local stringstrip = string.strip local stringformat = string.format local tableconcat = table.concat local lpegmatch = lpeg.match rst_directives.anonymous = 0 rst_directives.images = {} rst_directives.images.done = {} rst_directives.images.values = {} rst_directives.images.keys = { ["width"] = "width", ["size"] = "width", ["caption"] = "caption", ["alt"] = "caption", ["scale"] = "scale", } rst_directives.images.values.scale = function (orig) -- http://wiki.contextgarden.net/Reference/en/useexternalfigure -- scale=1000 is original size; to get 72%, use scale=720. return tonumber(orig) * 1000 end rst_directives.images.values.width = { ["fit"] = "\\hsize", ["hsize"] = "\\hsize", ["broad"] = "\\hsize", ["normal"] = "local", ["normal"] = "local", } -- we won't allow passing arbitrary setups to context rst_directives.images.permitted_setups = { "width", "scale" } local function img_setup (properties) local result = "" for _, prop in next, rst_directives.images.permitted_setups do if properties[prop] then result = result .. prop .. "=" .. properties[prop] .. "," end end if result ~= "" then result = "[" .. result .. "]" end return result end rst_directives.image = function(name, data) local inline_parser = rst_context.inline_parser local properties = {} local anon = false local rd = rst_directives if not data then -- this makes the “name” argument optional data = name rd.anonymous = rd.anonymous + 1 anon = true -- indicates a nameless picture name = "anonymous" .. rd.anonymous end properties.caption = name --properties.width = "\\local" local processed = "" -- stub; TODO do something useful with optional dimension specifications if type(data) == "table" then -- should always be true local p = helpers.patterns for i=1, #data do local str = data[i] local key, val key, val = lpegmatch(p.colon_keyval, str) local rdi = rst_directives.images if key and val then key = rdi.keys[key] -- sanitize key expression if type(rdi.values[key]) == "table" then val = rdi.values[key][val] elseif type(rdi.values[key]) == "function" then val = rdi.values[key](val) end properties[key] = val else processed = processed .. (str and str ~= "" and stringstrip(str)) end end end properties.setup = img_setup(properties) or "" data = processed processed = nil local img = "" local images_done = rd.images.done if not anon then if not images_done[name] then img = img .. stringformat([[ \useexternalfigure[%s][%s][] ]], name, data) images_done[name] = true end img = img .. stringformat([[ \def\RSTsubstitution%s{%% \placefigure[here]{%s}{\externalfigure[%s]%s} } ]], name, rst_context.escape(lpegmatch(inline_parser, properties.caption)), name, properties.setup) else -- image won't be referenced but used instantly img = img .. stringformat([[ \placefigure[here]{%s}{\externalfigure[%s]%s} ]], rst_context.escape(lpegmatch(inline_parser, properties.caption)), data, properties.setup) end return img end rst_directives.caution = function(raw) local inline_parser = rst_context.inline_parser rst_context.addsetups("dbend") rst_context.addsetups("caution") local text local first = true for i=1, #raw do local line = raw[i] if not lpegmatch(helpers.patterns.spacesonly, line) then if first then text = line first = false else text = text .. " " .. line end end end text = rst_context.escape(helpers.string.wrapat(lpegmatch(inline_parser, text))) return stringformat([[ \startRSTcaution %s \stopRSTcaution ]], text) end rst_directives.danger = function(raw) local inline_parser = rst_context.inline_parser rst_context.addsetups("dbend") rst_context.addsetups("danger") local text local first = true for i=1, #raw do local line = raw[i] if not lpegmatch(helpers.patterns.spacesonly, line) then if first then text = line first = false else text = text .. " " .. line end end end text = rst_context.escape(helpers.string.wrapat(lpegmatch(inline_parser, text))) return stringformat([[ \startRSTdanger %s \stopRSTdanger ]], text) end -- http://docutils.sourceforge.net/docs/ref/rst/directives.html rst_directives.DANGER = function(addendum) local result = "" for i=1, #addendum do local str = addendum[i] result = result .. (stringstrip(str)) end return stringformat([[ %% The Rabbit of Caerbannog \startlinecorrection \blank[force,big] \framed[frame=on, corner=round, rulethickness=5pt, align=middle, width=\hsize, frameoffset=.5em, backgroundoffset=1em, background=color, backgroundcolor=red, foreground=color, foregroundcolor=black]{%% \language[en-gb]\tfb\bf Follow only if ye be men of valour, for the entrance to this cave is guarded by a creature so foul, so cruel that no man yet has fought with it and lived. Bones of full fifty men lie strewn about its lair. So, brave knights, if you do doubt your courage or your strength, come no further, for death awaits you all with nasty, big, pointy teeth.%% \blank[force,big] %s%% } \blank[force,big] \stoplinecorrection ]], result) end rst_directives.mp = function(name, data) local mpcode = stringformat([[ \startreusableMPgraphic{%s} %s \stopreusableMPgraphic ]], name, data) mpcode = mpcode .. stringformat([[ \def\RSTsubstitution%s{%% \reuseMPgraphic{%s}%% } ]], name, name) return mpcode end --- There’s an issue with buffers leaving trailing spaces due to their --- implementation. --- http://archive.contextgarden.net/message/20111108.175913.1d994624.en.html rst_directives.ctx = function(name, data) local ctx = stringformat([[ \startbuffer[%s] %s\stopbuffer \def\RSTsubstitution%s{%% \getbuffer[%s]\removeunwantedspaces%% } ]], name, data, name, name) return ctx end rst_directives.lua = function(name, data) local luacode = stringformat([[ \startbuffer[%s] \startluacode %s \stopluacode \stopbuffer \def\RSTsubstitution%s{%% \getbuffer[%s]\removeunwantedspaces%% } ]], name, data, name, name) return luacode end -------------------------------------------------------------------------------- --- Experimental math directive -------------------------------------------------------------------------------- rst_directives.math = function (name, data) data = data or name local formula if type(data) == "table" then local last, i = #data, 1 while i <= last do local line = stringstrip(data[i]) if line and line ~= "" then formula = formula and formula .. " " .. line or line end i = i + 1 end end return stringformat([[ \startformula %s \stopformula ]], formula) end -------------------------------------------------------------------------------- --- End math directive -------------------------------------------------------------------------------- rst_directives.replace = function(name, data) return stringformat([[ \def\RSTsubstitution%s{%s} ]], name, data) end -------------------------------------------------------------------------------- --- Containers. -------------------------------------------------------------------------------- rst_directives.container = function(data) local inline_parser = rst_context.inline_parser local name, content = stringstrip(data[1]), "" if name == "" then name = "framed" end local tmp = { } for i=2, #data do tmp[#tmp+1] = data[i] end -- content |> concat |> match |> escape content = tableconcat(tmp, " ") content = lpegmatch(inline_parser, content) content = rst_context.escape(content) return stringformat([[ \ifcsname %s\endcsname%% \csname %s\endcsname%% {%s}%% \else {%s}%% \fi ]], name, name, content, content) end -- vim:ft=lua:sw=4:ts=4:expandtab