summaryrefslogtreecommitdiff
path: root/rst_context.lua
diff options
context:
space:
mode:
authorPhilipp Gesang <pgesang@ix.urz.uni-heidelberg.de>2010-09-02 22:14:43 +0200
committerPhilipp Gesang <pgesang@ix.urz.uni-heidelberg.de>2010-09-02 22:14:43 +0200
commit1c573f0f612b6fee3c13d45c15b9dacf990d8904 (patch)
treee5cb0a94ea9090f5f4325e21f763e7696b00988f /rst_context.lua
downloadcontext-rst-1c573f0f612b6fee3c13d45c15b9dacf990d8904.tar.gz
handles sections, paragraphs, transitions, targets
Diffstat (limited to 'rst_context.lua')
-rw-r--r--rst_context.lua200
1 files changed, 200 insertions, 0 deletions
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), <megas.kapaneus@gmail.com>
+-- 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