From 1c573f0f612b6fee3c13d45c15b9dacf990d8904 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 2 Sep 2010 22:14:43 +0200 Subject: handles sections, paragraphs, transitions, targets --- rst_context.lua | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 rst_context.lua (limited to 'rst_context.lua') diff --git a/rst_context.lua b/rst_context.lua new file mode 100644 index 0000000..6363dfe --- /dev/null +++ b/rst_context.lua @@ -0,0 +1,200 @@ +#!/usr/bin/env texlua +-------------------------------------------------------------------------------- +-- FILE: rst_context.lua +-- USAGE: ./rst_context.lua +-- DESCRIPTION: +-- OPTIONS: --- +-- REQUIREMENTS: --- +-- AUTHOR: Philipp Gesang (Phg), +-- VERSION: 1.0 +-- CREATED: 31/08/10 19:35:15 CEST +-------------------------------------------------------------------------------- +-- + + +require "lpeg" +local C, Cb, Cc, Cg, Cmt, Cp, Cs, Ct, P, R, S, V, match = lpeg.C, lpeg.Cb, lpeg.Cc, lpeg.Cg, lpeg.Cmt, lpeg.Cp, lpeg.Cs, lpeg.Ct, lpeg.P, lpeg.R, lpeg.S, lpeg.V, lpeg.match + +if not context then -- standard context lpeg stripper from l-string.lua + local stripper = P{ + [1] = "stripper", + stripper = V"space"^0 * C((V"space"^0 * V"nospace"^1)^0), + space = S(" \t\v\n"), + nospace = 1 - V"space", + } + function string.strip(str) + return stripper:match(str) or "" + end +end + + +local rst_context = {} +rst_context.collected_references = {} +rst_context.collected_adornments = {} +rst_context.last_section_level = 0 +rst_context.anonymous_links = 0 +rst_context.context_references = {} + +-- So we can use crefs[n][2] to refer to the place where the reference was +-- created. +local function get_context_reference (str) + local crefs = rst_context.context_references + refstring = "__contextref__" .. tostring(#crefs + 1) + crefs[#crefs + 1] = { refstring, str } + return refstring +end + +function rst_context.emphasis (str) + return [[{\\em ]] .. str .. [[}]] +end + +function rst_context.strong_emphasis (str) + return [[{\\sc ]] .. str .. [[}]] +end + +function rst_context.paragraph (str) + return "\n" .. [[\\startparagraph]] .. "\n" .. str .. "\n".. [[\\stopparagraph]] .. "\n" +end + +function rst_context.literal (str) + str = str:gsub([[\]], [[\\]]) -- evade escaping of backslashes + return [[\\type{]] .. str .. [[}]] +end + + +function rst_context.interpreted_text (...) + local tab = { ... } + --print (tab, #tab, tab[1], tab[2], tab[3]) + local role, str + role = tab[1]:match("^:(.*):$") or tab[3]:match("^:(.*):$") + str = tab[2] + + if not role then -- implicit role + role = "emphasis" + end + + --print(role, str) + + return rst_context[role](str) +end + +function rst_context.link_standalone (str) + return "\n" + .. [[\\goto{\\hyphenatedurl{]] + .. str + .. [[}}[url(]] + .. str + .. [=[)]]=] +end + +function rst_context.reference (str) + str = str:match("[^_]*") + local link = rst_context.collected_references[str] + if not link then -- TODO make warning instead + return([[{\\sc UNDEFINED REFERENCE ]] .. str .. [[}.]]) + end + return [[\\goto{]] + .. str + .. [[}[url(]] + .. link + .. [=[)]]=] +end + +function rst_context.target (tab) + --print("GOT ONE!") + --local tab = { ... } + local refs = rst_context.collected_references + local target = tab[#tab] -- Ct + C could be clearer but who cares + tab[#tab] = nil + + local function resolve_indirect (r) + if r and r:match(".*_$") then -- pointing elsewhere + return resolve_indirect (refs[r:match("(.*)_$")]) or "need another run!" -- TODO multiple runs && data collection + end + return r + end + + local function create_anonymous () + rst_context.anonymous_links = rst_context.anonymous_links + 1 + return "__anon__" .. rst_context.anonymous_links + end + + + target = resolve_indirect (target) + + for i=1,#tab do + local id = tab[i]:gsub("\\:",":") -- deescaping + id = id ~= "" and id or create_anonymous () + refs[id] = refs[id] or target + end + return "" +end + +function rst_context.escape (str) + return str:gsub("\\(.)", "%1") +end + +function rst_context.joinindented (tab) + return table.concat (tab, "") +end + +local sectionlevels = { + [1] = "chapter", + [2] = "section", + [3] = "subsection", + [4] = "subsubsection", + [5] = "subsubsubsection", +} + +local function get_line_pattern (chr) + return P(chr)^1 * (-P(1)) +end + +function rst_context.section (...) -- TODO general cleanup; move validity + local tab = { ... } -- checking to parser. + local section, str = true, "" + local adornchar + if #tab == 3 then -- TODO use unicode length with ConTeXt + --print(">>"..tab[1].."<>"..tab[2].."<<") + adornchar = tab[1]:sub(1,1) + -- overline == underline && len(overline) = len(sectionstring) + section = tab[1] == tab[3] and #tab[1] >= #tab[2] + -- if overline consists only of one char then keep truth value else + -- false + section = get_line_pattern(adornchar):match(tab[1]) ~= nil and section + str = string.strip(tab[2]) + else -- no overline + --print(">>"..tab[1].."<>"..tab[2].."<<") + adornchar = tab[2]:sub(1,1) + section = #tab[1] <= #tab[2] + section = get_line_pattern(adornchar):match(tab[2]) ~= nil and section + str = tab[1] + end + + if section then -- determine level + local level = rst_context.last_section_level + local rca = rst_context.collected_adornments + if rca[adornchar] then + level = rca[adornchar] + else + level = level + 1 + rca[adornchar] = level + rst_context.last_section_level = level + end + + ref = get_context_reference (str) + + str = string.format("\n\\\\%s[%s]{%s}\n", sectionlevels[level], ref, str) + end + + return section and str or "" +end + +-- Prime time for the fancybreak module. +function rst_context.transition (str) + return "\n\\hrule\n" +end + + + +return rst_context -- cgit v1.2.3