# HG changeset patch # User Paul Boddie # Date 1534175716 -7200 # Node ID 3745c9e20358fcd5f78ced3212ce26b2ba3252d7 # Parent 60323aaf9b31696fb4eebd63e47023c0d5b10a2b Added elementary theming support, making fragment output an option as opposed to being the default in the conversion script. diff -r 60323aaf9b31 -r 3745c9e20358 convert.py --- a/convert.py Mon Aug 13 17:11:54 2018 +0200 +++ b/convert.py Mon Aug 13 17:55:16 2018 +0200 @@ -1,7 +1,7 @@ #!/usr/bin/env python from moinformat import make_input, make_linker, make_output, make_parser, \ - make_serialiser, parse, serialise + make_serialiser, make_theme, parse, serialise from os.path import split import sys @@ -36,11 +36,13 @@ mappings = [] output_dirs = [] output_encodings = [] + theme_names = [] pagenames = [] # Flags. all = False + fragment = False macros = False tree = False @@ -61,6 +63,11 @@ elif arg == "--all": all = True + # Detect fragment output (if serialising). + + elif arg == "--fragment": + fragment = True + # Switch to collecting formats. elif arg == "--format": @@ -115,6 +122,12 @@ l = pagenames continue + # Switch to collecting theme names. + + elif arg == "--theme": + l = theme_names + continue + # Collect options and arguments. else: @@ -140,7 +153,7 @@ input_encoding = getvalue(input_encodings) output_encoding = getvalue(output_encodings) - # Obtain the input and output locations. + # Obtain the input and output locations and contexts. input_dir = getvalue(input_dirs) output_dir = getvalue(output_dirs) @@ -159,6 +172,12 @@ output = make_output(output_context, {"encoding" : output_encoding, "filename" : output_dir}) + # Obtain a theme name. + + theme_name = not fragment and (getvalue(theme_names) or "default") or None + + theme = None + # Treat filenames as pagenames if an input directory is indicated and if no # pagenames are explicitly specified. @@ -223,6 +242,16 @@ serialiser = make_serialiser(format, output, linker, pagename) outtext = serialise(d, serialiser) + # Obtain a theme object for theming. + + theme = theme_name and make_theme("%s.%s" % (theme_name, format), + output, linker, pagename) + + # 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. @@ -232,6 +261,11 @@ output.writepage(outtext, pagename) print >>sys.stderr, pagename + # Install any theme resources. + + if theme: + theme.install_resources() + if __name__ == "__main__": main() diff -r 60323aaf9b31 -r 3745c9e20358 moinformat/__init__.py --- a/moinformat/__init__.py Mon Aug 13 17:11:54 2018 +0200 +++ b/moinformat/__init__.py Mon Aug 13 17:55:16 2018 +0200 @@ -24,5 +24,6 @@ from moinformat.output import make_output from moinformat.parsers import get_parser, make_parser, parse from moinformat.serialisers import get_serialiser, make_serialiser, serialise +from moinformat.themes import make_theme # vim: tabstop=4 expandtab shiftwidth=4 diff -r 60323aaf9b31 -r 3745c9e20358 moinformat/themes/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/moinformat/themes/__init__.py Mon Aug 13 17:55:16 2018 +0200 @@ -0,0 +1,48 @@ +#!/usr/bin/env python + +""" +Theming support. + +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.manifest import themes + +# Top-level functions. + +def get_theme(name): + + """ + Return the theme class with the given 'name' or None if no such class is + found. + """ + + return themes.get(name) + +def make_theme(name, output, linker, pagename): + + """ + Return a theme of the type indicated by 'name', employing the given 'output' + context, 'linker' and 'pagename'. + """ + + theme_cls = get_theme(name) + if not theme_cls: + return None + + return theme_cls(output, linker, pagename) + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r 60323aaf9b31 -r 3745c9e20358 moinformat/themes/common.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/moinformat/themes/common.py Mon Aug 13 17:55:16 2018 +0200 @@ -0,0 +1,97 @@ +#!/usr/bin/env python + +""" +Theming common 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 os import listdir, makedirs +from os.path import exists, isfile, join, split +from shutil import copy + +class Theme: + + "A common theme abstraction." + + def __init__(self, output, linker, pagename): + + """ + Initialise the theme with the given 'output' context, 'linker' and + 'pagename'. + """ + + self.output = output + self.linker = linker + self.pagename = pagename + + def apply(self, text): + + "Apply this theme to the given 'text', returning a themed version." + + return text + + def get_resource_base(self): + + "Return the filesystem base of resources for instances of this class." + + return split(self.__class__.origin)[0] + + def get_resource(self, filename): + + "Return the complete path for the resource with the given 'filename'." + + base = self.get_resource_base() + return join(base, filename) + + def install_resource(self, filename, target=None): + + """ + Install the resource with the given 'filename' into a location having + the given 'target' name (or 'filename' if 'target' is omitted). + """ + + pathname = self.get_resource(filename) + outpath = self.output.get_filename(target or filename) + + self.copy(pathname, outpath) + + def copy(self, pathname, outpath): + + "Copy 'pathname' to 'outpath'." + + if isfile(pathname): + outdir = split(outpath)[0] + if outdir and not exists(outdir): + makedirs(outdir) + copy(pathname, outpath) + else: + if not exists(outpath): + makedirs(outpath) + for filename in listdir(pathname): + self.copy(join(pathname, filename), join(outpath, filename)) + + def load_resource(self, filename): + + "Return the textual content of the resource with the given 'filename'." + + f = open(self.get_resource(filename)) + try: + return f.read() + finally: + f.close() + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r 60323aaf9b31 -r 3745c9e20358 moinformat/themes/default/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/moinformat/themes/default/__init__.py Mon Aug 13 17:55:16 2018 +0200 @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +""" +A default 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 60323aaf9b31 -r 3745c9e20358 moinformat/themes/default/css/common.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/moinformat/themes/default/css/common.css Mon Aug 13 17:55:16 2018 +0200 @@ -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 60323aaf9b31 -r 3745c9e20358 moinformat/themes/default/html.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/moinformat/themes/default/html.py Mon Aug 13 17:55:16 2018 +0200 @@ -0,0 +1,52 @@ +#!/usr/bin/env python + +""" +A default 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.common import Theme + +class DefaultHTMLTheme(Theme): + + "A default 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.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 60323aaf9b31 -r 3745c9e20358 moinformat/themes/default/template.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/moinformat/themes/default/template.html Mon Aug 13 17:55:16 2018 +0200 @@ -0,0 +1,11 @@ + + + +%(title)s + + + + +%(text)s + + diff -r 60323aaf9b31 -r 3745c9e20358 moinformat/themes/manifest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/moinformat/themes/manifest.py Mon Aug 13 17:55:16 2018 +0200 @@ -0,0 +1,35 @@ +#!/usr/bin/env python + +""" +Theme implementation manifest. + +Copyright (C) 2017, 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.imports import get_extensions, get_mapping, get_modules + +# Define an attribute mapping names to modules. + +modules = get_modules(__file__, __name__) + +# Obtain all themes. + +# Use module paths to register the contexts: +# theme_name.output_format -> theme + +themes = get_mapping(modules, lambda n, m: n, lambda m: m.theme) + +# vim: tabstop=4 expandtab shiftwidth=4