# HG changeset patch # User Paul Boddie # Date 1543269592 -3600 # Node ID f67f4d353edcc7a8e31f42b714db176df6b7c1f3 # Parent 9ce079567ad8f827bde79827dcd603d3526b949e# Parent a414533ba44ac367e7b839fca8d19cecdc47a036 Merged changes from the default branch. diff -r 9ce079567ad8 -r f67f4d353edc convert.py --- a/convert.py Sun Nov 25 16:59:19 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,265 +0,0 @@ -#!/usr/bin/env python - -from moinformat import make_parser, make_serialiser, Metadata, parse, serialise -from os.path import split -import sys - -def getmapping(mappings): - mapping = {} - key = None - - for arg in mappings: - if key is None: - key = arg - else: - mapping[key] = arg - key = None - - return mapping - -def getvalue(values, default=None): - return values and values[0] or default - -def main(): - dirname, progname = split(sys.argv[0]) - args = sys.argv[1:] - - # Option values. - - l = filenames = [] - formats = [] - input_dir_types = [] - input_dirs = [] - input_encodings = [] - input_page_seps = [] - mappings = [] - output_dirs = [] - output_encodings = [] - theme_names = [] - pagenames = [] - root_pagenames = [] - - # Flags. - - all = False - fragment = False - macros = False - tree = False - - for arg in args: - - # Detect tree output. - - if arg == "--tree": - tree = True - - # Detect macro evaluation. - - elif arg == "--macros": - macros = True - - # Detect all documents. - - elif arg == "--all": - all = True - - # Detect fragment output (if serialising). - - elif arg == "--fragment": - fragment = True - - # Switch to collecting formats. - - elif arg == "--format": - l = formats - continue - - # Switch to collecting input locations. - - elif arg == "--input-dir": - l = input_dirs - continue - - # Switch to collecting input context types. - - elif arg == "--input-dir-type": - l = input_dir_types - continue - - # Switch to collecting input encodings. - - elif arg == "--input-encoding": - l = input_encodings - continue - - # Switch to collecting input page hierarchy separators. - - elif arg == "--input-page-sep": - l = input_page_seps - continue - - # Switch to collecting mappings. - - elif arg == "--mapping": - l = mappings - continue - - # Switch to collecting output locations. - - elif arg == "--output-dir": - l = output_dirs - continue - - # Switch to collecting output encodings. - - elif arg == "--output-encoding": - l = output_encodings - continue - - # Switch to collecting page names. - - elif arg == "--pagename": - l = pagenames - continue - - # Switch to collecting root page names. - - elif arg == "--root": - l = root_pagenames - continue - - # Switch to collecting theme names. - - elif arg == "--theme": - l = theme_names - continue - - # Collect options and arguments. - - else: - l.append(arg) - - # Collect multiple mappings. - - if l is mappings: - continue - - # Collect filenames normally. - - l = filenames - - format = formats and formats[0] or "html" - input_dir = getvalue(input_dirs) - output_dir = getvalue(output_dirs) - - # Define metadata. - - metadata = Metadata({ - "input_context" : input_dir and \ - getvalue(input_dir_types, "directory") or \ - "standalone", - "input_encoding" : getvalue(input_encodings), - "input_filename" : input_dir, - "input_separator" : getvalue(input_page_seps), - "link_format" : format, - "mapping" : getmapping(mappings), - "output_context" : output_dir and "directory" or "standalone", - "output_encoding" : getvalue(output_encodings), - "output_format" : format, - "output_filename" : output_dir, - "root_pagename" : getvalue(root_pagenames, "FrontPage"), - "theme_name" : not fragment and \ - "%s.%s" % (getvalue(theme_names, "default"), format) or None, - }) - - # Define the input context and theme. - - input = metadata.get_input() - theme = metadata.get_theme() - - # Treat filenames as pagenames if an input directory is indicated and if no - # pagenames are explicitly specified. - - if input_dir: - if pagenames: - print >>sys.stderr, """\ -Explicit pagenames (indicated using --pagename) are only to be specified when -providing filenames without an input directory (indicated using --input-dir). - -To indicate pagenames within an input directory, omit any --pagename flags.""" - sys.exit(1) - - if all: - if filenames: - print >>sys.stderr, """\ -Using --all overrides any indicated pagenames. Either --all or the filenames -should be omitted.""" - sys.exit(1) - else: - filenames = input.all() - - pagenames = filenames - filenames = [] - - # Open each file or page, parse the content, serialise the document. - - for pagename, filename in map(None, pagenames, filenames): - - # Define a pagename if missing. - - pagename = pagename or split(filename)[-1] - metadata.set("pagename", pagename) - - # Read either from a filename or using a pagename. - - if filename: - pagetext = input.readfile(filename) - else: - pagetext = input.readpage(pagename) - - # Parse the page content. - - p = make_parser(metadata) - d = parse(pagetext, p) - - if macros: - p.evaluate_macros() - - # Show a document tree for debugging purposes, if requested. - - if tree: - print d.prettyprint() - continue - - # Otherwise, serialise the document. - - # Obtain a serialiser using the configuration. - - serialiser = make_serialiser(metadata) - outtext = serialise(d, serialiser) - - # With a theme, apply it to the text. - - if theme: - outtext = theme.apply(outtext) - - # If reading from a file, show the result. Otherwise, write to the - # output context. - - output = metadata.get_output() - - if not output.can_write(): - print outtext - else: - output.writepage(outtext, pagename) - print >>sys.stderr, pagename - - # Install any theme resources. - - if theme: - theme.install_resources() - -if __name__ == "__main__": - main() - -# vim: tabstop=4 expandtab shiftwidth=4 diff -r 9ce079567ad8 -r f67f4d353edc moinconvert --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/moinconvert Mon Nov 26 22:59:52 2018 +0100 @@ -0,0 +1,313 @@ +#!/usr/bin/env python + +""" +Moin wiki format converter. + +Copyright (C) 2018 Paul Boddie + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . +""" + +from moinformat import make_parser, make_serialiser, Metadata, parse, serialise +from os.path import split +import sys + +# Long messages. + +message_all_with_filenames = """\ +Using --all overrides any indicated pagenames. Either --all or the filenames +should be omitted.""" + +message_explicit_pagenames = """\ +Explicit pagenames (indicated using --pagename) are only to be specified when +providing filenames without an input directory (indicated using --input-dir). + +To indicate pagenames within an input directory, omit any --pagename flags.""" + + + +# Options management. + +def getmapping(mappings): + + """ + Return the given 'mappings' - a collection of key-then-value items - as a + dictionary. + """ + + mapping = {} + key = None + + for arg in mappings: + if key is None: + key = arg + else: + mapping[key] = arg + key = None + + return mapping + +def getvalue(values, default=None): + + """ + Return the first value from 'values' or 'default' if 'values' is empty or + the first value tests as false. + """ + + return values and values[0] or default + + + +# Main program. + +def main(): + + "Interpret program options and perform the conversion." + + dirname, progname = split(sys.argv[0]) + args = sys.argv[1:] + + # Option values. + + l = filenames = [] + formats = [] + input_dir_types = [] + input_dirs = [] + input_encodings = [] + input_page_seps = [] + mappings = [] + output_dirs = [] + output_encodings = [] + theme_names = [] + pagenames = [] + root_pagenames = [] + + # Flags. + + all = False + fragment = False + macros = False + tree = False + + for arg in args: + + # Detect tree output. + + if arg == "--tree": + tree = True + + # Detect macro evaluation. + + elif arg == "--macros": + macros = True + + # Detect all documents. + + elif arg == "--all": + all = True + + # Detect fragment output (if serialising). + + elif arg == "--fragment": + fragment = True + + # Switch to collecting formats. + + elif arg == "--format": + l = formats + continue + + # Switch to collecting input locations. + + elif arg == "--input-dir": + l = input_dirs + continue + + # Switch to collecting input context types. + + elif arg == "--input-dir-type": + l = input_dir_types + continue + + # Switch to collecting input encodings. + + elif arg == "--input-encoding": + l = input_encodings + continue + + # Switch to collecting input page hierarchy separators. + + elif arg == "--input-page-sep": + l = input_page_seps + continue + + # Switch to collecting mappings. + + elif arg == "--mapping": + l = mappings + continue + + # Switch to collecting output locations. + + elif arg == "--output-dir": + l = output_dirs + continue + + # Switch to collecting output encodings. + + elif arg == "--output-encoding": + l = output_encodings + continue + + # Switch to collecting page names. + + elif arg == "--pagename": + l = pagenames + continue + + # Switch to collecting root page names. + + elif arg == "--root": + l = root_pagenames + continue + + # Switch to collecting theme names. + + elif arg == "--theme": + l = theme_names + continue + + # Collect options and arguments. + + else: + l.append(arg) + + # Collect multiple mappings. + + if l is mappings: + continue + + # Collect filenames normally. + + l = filenames + + format = formats and formats[0] or "html" + input_dir = getvalue(input_dirs) + output_dir = getvalue(output_dirs) + + # Define metadata. + + metadata = Metadata({ + "input_context" : input_dir and \ + getvalue(input_dir_types, "directory") or \ + "standalone", + "input_encoding" : getvalue(input_encodings), + "input_filename" : input_dir, + "input_separator" : getvalue(input_page_seps), + "link_format" : format, + "mapping" : getmapping(mappings), + "output_context" : output_dir and "directory" or "standalone", + "output_encoding" : getvalue(output_encodings), + "output_format" : format, + "output_filename" : output_dir, + "root_pagename" : getvalue(root_pagenames, "FrontPage"), + "theme_name" : not fragment and \ + "%s.%s" % (getvalue(theme_names, "default"), format) or None, + }) + + # Define the input context and theme. + + input = metadata.get_input() + theme = metadata.get_theme() + + # Treat filenames as pagenames if an input directory is indicated and if no + # pagenames are explicitly specified. + + if input_dir: + if pagenames: + print >>sys.stderr, message_explicit_pagenames + sys.exit(1) + + if all: + if filenames: + print >>sys.stderr, message_all_with_filenames + sys.exit(1) + else: + filenames = input.all() + + pagenames = filenames + filenames = [] + + # Open each file or page, parse the content, serialise the document. + + for pagename, filename in map(None, pagenames, filenames): + + # Define a pagename if missing. + + pagename = pagename or split(filename)[-1] + metadata.set("pagename", pagename) + + # Read either from a filename or using a pagename. + + if filename: + pagetext = input.readfile(filename) + else: + pagetext = input.readpage(pagename) + + # Parse the page content. + + p = make_parser(metadata) + d = parse(pagetext, p) + + if macros: + p.evaluate_macros() + + # Show a document tree for debugging purposes, if requested. + + if tree: + print d.prettyprint() + continue + + # Otherwise, serialise the document. + + # Obtain a serialiser using the configuration. + + serialiser = make_serialiser(metadata) + outtext = serialise(d, serialiser) + + # With a theme, apply it to the text. + + if theme: + outtext = theme.apply(outtext) + + # If reading from a file, show the result. Otherwise, write to the + # output context. + + output = metadata.get_output() + + if not output.can_write(): + print outtext + else: + output.writepage(outtext, pagename) + print >>sys.stderr, pagename + + # Install any theme resources. + + if theme: + theme.install_resources() + +if __name__ == "__main__": + main() + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r 9ce079567ad8 -r f67f4d353edc moinformat/parsers/common.py --- a/moinformat/parsers/common.py Sun Nov 25 16:59:19 2018 +0100 +++ b/moinformat/parsers/common.py Mon Nov 26 22:59:52 2018 +0100 @@ -390,11 +390,9 @@ region = Region([], level, indent, type) - # Parse section headers and directives, then parse according to region - # type. + # Parse section headers, then parse according to region type. self.parse_region_header(region) - self.parse_region_directives(region) self.parse_region_type(region) return region @@ -411,6 +409,12 @@ if not parser: region.transparent = False parser = parser or self.get_parser("moin") + + # Only parse directives if the region is transparent. + + if region.transparent: + self.parse_region_directives(region) + parser.parse_region_content(self.items, region) def parse_region_header(self, region): diff -r 9ce079567ad8 -r f67f4d353edc moinformat/themes/default/css/all.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/moinformat/themes/default/css/all.css Mon Nov 26 22:59:52 2018 +0100 @@ -0,0 +1,9 @@ +table { + border-collapse: collapse; + margin: 0.5em 0 0.5em 0; +} + +table td { + border: 1px solid #000; + padding: 0.5em; +} diff -r 9ce079567ad8 -r f67f4d353edc moinformat/themes/default/css/common.css --- a/moinformat/themes/default/css/common.css Sun Nov 25 16:59:19 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -table { - border-collapse: collapse; - margin: 0.5em 0 0.5em 0; -} - -table td { - border: 1px solid #000; - padding: 0.5em; -} diff -r 9ce079567ad8 -r f67f4d353edc moinformat/themes/default/html.py --- a/moinformat/themes/default/html.py Sun Nov 25 16:59:19 2018 +0100 +++ b/moinformat/themes/default/html.py Mon Nov 26 22:59:52 2018 +0100 @@ -19,34 +19,15 @@ this program. If not, see . """ -from moinformat.themes.common import Theme +from moinformat.themes.html import HTMLTheme -class DefaultHTMLTheme(Theme): +class DefaultHTMLTheme(HTMLTheme): - "A default theme." + "A default HTML theme." name = "html" origin = __file__ - def apply(self, text): - - "Apply this theme to the given 'text', returning a themed version." - - template = self.load_resource("template.html") - subs = { - "encoding" : self.output.encoding, - "root" : self.linker.get_top_level() or ".", - "text" : text, - "title" : self.metadata.get("pagename"), - } - return template % subs - - def install_resources(self): - - "Install resources for this theme." - - self.install_resource("css", "_css") - theme = DefaultHTMLTheme # vim: tabstop=4 expandtab shiftwidth=4 diff -r 9ce079567ad8 -r f67f4d353edc moinformat/themes/default/template.html --- a/moinformat/themes/default/template.html Sun Nov 25 16:59:19 2018 +0100 +++ b/moinformat/themes/default/template.html Mon Nov 26 22:59:52 2018 +0100 @@ -2,7 +2,7 @@ %(title)s - +%(links)s diff -r 9ce079567ad8 -r f67f4d353edc moinformat/themes/html.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/moinformat/themes/html.py Mon Nov 26 22:59:52 2018 +0100 @@ -0,0 +1,85 @@ +#!/usr/bin/env python + +""" +Common HTML theme functionality. + +Copyright (C) 2018 Paul Boddie + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . +""" + +from moinformat.themes.common import Theme +from os import listdir +from os.path import splitext + +class HTMLTheme(Theme): + + "A common HTML theme abstraction." + + # Support a collection of links to stylesheets provided by each theme. + + link = '\n' + + def get_links(self, subs): + + "Using 'subs', return a string containing markup linking to resources." + + d = {} + d.update(subs) + + links = [] + + for filename in listdir(self.get_resource("css")): + + # Only link to CSS files. + + basename, ext = splitext(filename) + if ext != ".css": + continue + + # Filenames can have the form .css or -.css to + # set the media type. + + t = basename.split("-", 1) + + d["media"] = t[0] or "all" + d["filename"] = filename + + links.append(self.link % d) + + return "".join(links) + + # Public methods. + + def apply(self, text): + + "Apply this theme to the given 'text', returning a themed version." + + template = self.load_resource("template.html") + subs = { + "encoding" : self.output.encoding, + "root" : self.linker.get_top_level() or ".", + "text" : text, + "title" : self.metadata.get("pagename"), + } + subs["links"] = self.get_links(subs) + return template % subs + + def install_resources(self): + + "Install resources for this theme." + + self.install_resource("css", "_css") + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r 9ce079567ad8 -r f67f4d353edc moinformat/themes/manifest.py --- a/moinformat/themes/manifest.py Sun Nov 25 16:59:19 2018 +0100 +++ b/moinformat/themes/manifest.py Mon Nov 26 22:59:52 2018 +0100 @@ -21,10 +21,18 @@ from moinformat.imports import get_extensions, get_mapping, get_modules +ignore = ["html"] + # Define an attribute mapping names to modules. modules = get_modules(__file__, __name__) +# Filter out modules in this package that provide common functionality. + +for m in ignore: + if modules.has_key(m): + del modules[m] + # Obtain all themes. # Use module paths to register the contexts: diff -r 9ce079567ad8 -r f67f4d353edc moinformat/themes/mercurial/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/moinformat/themes/mercurial/__init__.py Mon Nov 26 22:59:52 2018 +0100 @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +""" +A Mercurial-inspired theme. + +Copyright (C) 2018 Paul Boddie + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . +""" + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r 9ce079567ad8 -r f67f4d353edc moinformat/themes/mercurial/css/all.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/moinformat/themes/mercurial/css/all.css Mon Nov 26 22:59:52 2018 +0100 @@ -0,0 +1,80 @@ +html { + background-color: white; + color: black; + font-family: sans-serif; + font-size: 1em; +} + +body { + margin: 0 5em; + padding: 0; + border: 0; +} + +a, img { + border: 0; +} + +/* List formatting. */ + +dl, ol, ul { + padding: 0 1em; + margin: 0 0.5em; +} + +li p { + margin: 0.1em 0; +} + +dt { + margin-top: 0.25em; + font-weight: bold; +} + +dd { + margin-top: 0; + margin-bottom: 0; +} + +dd p { + margin: 0.1em 0; +} + +/* Table formatting. */ + +table { + margin: 0.5em 0 0 0.5em; + border-collapse: collapse; +} + +th, td { + padding: 0.25em 0.5em 0.25em 0.5em; + border: 1pt solid #ADB9CC; +} + +td p { + margin: 0; + padding: 0; +} + +/* Preformatted text. */ + +pre { + border: 1pt solid #AEBDCC; + background-color: #F3F5F7; + padding: 5pt; + font-family: courier, monospace; + white-space: pre; +} + +/* Monospace inline text frequently looks smaller than the surrounding text. */ + +tt { + font-size: 120%; +} + +/* Embedded objects. */ + +object { + margin: 1em 0; +} diff -r 9ce079567ad8 -r f67f4d353edc moinformat/themes/mercurial/css/print.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/moinformat/themes/mercurial/css/print.css Mon Nov 26 22:59:52 2018 +0100 @@ -0,0 +1,13 @@ +html { + font-family: Times, serif; + font-size: 12pt; +} + +body { + margin: 1.5cm; +} + +a, a:visited { + color: black; + text-decoration: none; +} diff -r 9ce079567ad8 -r f67f4d353edc moinformat/themes/mercurial/css/screen.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/moinformat/themes/mercurial/css/screen.css Mon Nov 26 22:59:52 2018 +0100 @@ -0,0 +1,12 @@ +body { + font-family: Helvetica, Verdana, Arial, sans-serif; + color: #111; +} + +a:link, a:visited { color: #00b5f1; text-decoration: none; } +a:link:hover, a:link:active, a:link:focus, +a:visited:hover, a:visited:active, a:visited:focus { text-decoration: underline; } + +h1 { font-size: 2em; } +h2 { font-size: 1.6em; } +h3 { font-size: 1.3em; } diff -r 9ce079567ad8 -r f67f4d353edc moinformat/themes/mercurial/html.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/moinformat/themes/mercurial/html.py Mon Nov 26 22:59:52 2018 +0100 @@ -0,0 +1,33 @@ +#!/usr/bin/env python + +""" +A Mercurial-inspired theme for HTML output. + +Copyright (C) 2018 Paul Boddie + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . +""" + +from moinformat.themes.html import HTMLTheme + +class MercurialHTMLTheme(HTMLTheme): + + "A Mercurial-inspired HTML theme." + + name = "html" + origin = __file__ + +theme = MercurialHTMLTheme + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r 9ce079567ad8 -r f67f4d353edc moinformat/themes/mercurial/template.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/moinformat/themes/mercurial/template.html Mon Nov 26 22:59:52 2018 +0100 @@ -0,0 +1,11 @@ + + + +%(title)s +%(links)s + + + +%(text)s + +