1.1 --- a/convert.py Mon Aug 13 17:11:54 2018 +0200
1.2 +++ b/convert.py Mon Aug 13 17:55:16 2018 +0200
1.3 @@ -1,7 +1,7 @@
1.4 #!/usr/bin/env python
1.5
1.6 from moinformat import make_input, make_linker, make_output, make_parser, \
1.7 - make_serialiser, parse, serialise
1.8 + make_serialiser, make_theme, parse, serialise
1.9 from os.path import split
1.10 import sys
1.11
1.12 @@ -36,11 +36,13 @@
1.13 mappings = []
1.14 output_dirs = []
1.15 output_encodings = []
1.16 + theme_names = []
1.17 pagenames = []
1.18
1.19 # Flags.
1.20
1.21 all = False
1.22 + fragment = False
1.23 macros = False
1.24 tree = False
1.25
1.26 @@ -61,6 +63,11 @@
1.27 elif arg == "--all":
1.28 all = True
1.29
1.30 + # Detect fragment output (if serialising).
1.31 +
1.32 + elif arg == "--fragment":
1.33 + fragment = True
1.34 +
1.35 # Switch to collecting formats.
1.36
1.37 elif arg == "--format":
1.38 @@ -115,6 +122,12 @@
1.39 l = pagenames
1.40 continue
1.41
1.42 + # Switch to collecting theme names.
1.43 +
1.44 + elif arg == "--theme":
1.45 + l = theme_names
1.46 + continue
1.47 +
1.48 # Collect options and arguments.
1.49
1.50 else:
1.51 @@ -140,7 +153,7 @@
1.52 input_encoding = getvalue(input_encodings)
1.53 output_encoding = getvalue(output_encodings)
1.54
1.55 - # Obtain the input and output locations.
1.56 + # Obtain the input and output locations and contexts.
1.57
1.58 input_dir = getvalue(input_dirs)
1.59 output_dir = getvalue(output_dirs)
1.60 @@ -159,6 +172,12 @@
1.61 output = make_output(output_context, {"encoding" : output_encoding,
1.62 "filename" : output_dir})
1.63
1.64 + # Obtain a theme name.
1.65 +
1.66 + theme_name = not fragment and (getvalue(theme_names) or "default") or None
1.67 +
1.68 + theme = None
1.69 +
1.70 # Treat filenames as pagenames if an input directory is indicated and if no
1.71 # pagenames are explicitly specified.
1.72
1.73 @@ -223,6 +242,16 @@
1.74 serialiser = make_serialiser(format, output, linker, pagename)
1.75 outtext = serialise(d, serialiser)
1.76
1.77 + # Obtain a theme object for theming.
1.78 +
1.79 + theme = theme_name and make_theme("%s.%s" % (theme_name, format),
1.80 + output, linker, pagename)
1.81 +
1.82 + # With a theme, apply it to the text.
1.83 +
1.84 + if theme:
1.85 + outtext = theme.apply(outtext)
1.86 +
1.87 # If reading from a file, show the result. Otherwise, write to the
1.88 # output context.
1.89
1.90 @@ -232,6 +261,11 @@
1.91 output.writepage(outtext, pagename)
1.92 print >>sys.stderr, pagename
1.93
1.94 + # Install any theme resources.
1.95 +
1.96 + if theme:
1.97 + theme.install_resources()
1.98 +
1.99 if __name__ == "__main__":
1.100 main()
1.101
2.1 --- a/moinformat/__init__.py Mon Aug 13 17:11:54 2018 +0200
2.2 +++ b/moinformat/__init__.py Mon Aug 13 17:55:16 2018 +0200
2.3 @@ -24,5 +24,6 @@
2.4 from moinformat.output import make_output
2.5 from moinformat.parsers import get_parser, make_parser, parse
2.6 from moinformat.serialisers import get_serialiser, make_serialiser, serialise
2.7 +from moinformat.themes import make_theme
2.8
2.9 # vim: tabstop=4 expandtab shiftwidth=4
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/moinformat/themes/__init__.py Mon Aug 13 17:55:16 2018 +0200
3.3 @@ -0,0 +1,48 @@
3.4 +#!/usr/bin/env python
3.5 +
3.6 +"""
3.7 +Theming support.
3.8 +
3.9 +Copyright (C) 2018 Paul Boddie <paul@boddie.org.uk>
3.10 +
3.11 +This program is free software; you can redistribute it and/or modify it under
3.12 +the terms of the GNU General Public License as published by the Free Software
3.13 +Foundation; either version 3 of the License, or (at your option) any later
3.14 +version.
3.15 +
3.16 +This program is distributed in the hope that it will be useful, but WITHOUT
3.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
3.18 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
3.19 +details.
3.20 +
3.21 +You should have received a copy of the GNU General Public License along with
3.22 +this program. If not, see <http://www.gnu.org/licenses/>.
3.23 +"""
3.24 +
3.25 +from moinformat.themes.manifest import themes
3.26 +
3.27 +# Top-level functions.
3.28 +
3.29 +def get_theme(name):
3.30 +
3.31 + """
3.32 + Return the theme class with the given 'name' or None if no such class is
3.33 + found.
3.34 + """
3.35 +
3.36 + return themes.get(name)
3.37 +
3.38 +def make_theme(name, output, linker, pagename):
3.39 +
3.40 + """
3.41 + Return a theme of the type indicated by 'name', employing the given 'output'
3.42 + context, 'linker' and 'pagename'.
3.43 + """
3.44 +
3.45 + theme_cls = get_theme(name)
3.46 + if not theme_cls:
3.47 + return None
3.48 +
3.49 + return theme_cls(output, linker, pagename)
3.50 +
3.51 +# vim: tabstop=4 expandtab shiftwidth=4
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/moinformat/themes/common.py Mon Aug 13 17:55:16 2018 +0200
4.3 @@ -0,0 +1,97 @@
4.4 +#!/usr/bin/env python
4.5 +
4.6 +"""
4.7 +Theming common functionality.
4.8 +
4.9 +Copyright (C) 2018 Paul Boddie <paul@boddie.org.uk>
4.10 +
4.11 +This program is free software; you can redistribute it and/or modify it under
4.12 +the terms of the GNU General Public License as published by the Free Software
4.13 +Foundation; either version 3 of the License, or (at your option) any later
4.14 +version.
4.15 +
4.16 +This program is distributed in the hope that it will be useful, but WITHOUT
4.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
4.18 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
4.19 +details.
4.20 +
4.21 +You should have received a copy of the GNU General Public License along with
4.22 +this program. If not, see <http://www.gnu.org/licenses/>.
4.23 +"""
4.24 +
4.25 +from os import listdir, makedirs
4.26 +from os.path import exists, isfile, join, split
4.27 +from shutil import copy
4.28 +
4.29 +class Theme:
4.30 +
4.31 + "A common theme abstraction."
4.32 +
4.33 + def __init__(self, output, linker, pagename):
4.34 +
4.35 + """
4.36 + Initialise the theme with the given 'output' context, 'linker' and
4.37 + 'pagename'.
4.38 + """
4.39 +
4.40 + self.output = output
4.41 + self.linker = linker
4.42 + self.pagename = pagename
4.43 +
4.44 + def apply(self, text):
4.45 +
4.46 + "Apply this theme to the given 'text', returning a themed version."
4.47 +
4.48 + return text
4.49 +
4.50 + def get_resource_base(self):
4.51 +
4.52 + "Return the filesystem base of resources for instances of this class."
4.53 +
4.54 + return split(self.__class__.origin)[0]
4.55 +
4.56 + def get_resource(self, filename):
4.57 +
4.58 + "Return the complete path for the resource with the given 'filename'."
4.59 +
4.60 + base = self.get_resource_base()
4.61 + return join(base, filename)
4.62 +
4.63 + def install_resource(self, filename, target=None):
4.64 +
4.65 + """
4.66 + Install the resource with the given 'filename' into a location having
4.67 + the given 'target' name (or 'filename' if 'target' is omitted).
4.68 + """
4.69 +
4.70 + pathname = self.get_resource(filename)
4.71 + outpath = self.output.get_filename(target or filename)
4.72 +
4.73 + self.copy(pathname, outpath)
4.74 +
4.75 + def copy(self, pathname, outpath):
4.76 +
4.77 + "Copy 'pathname' to 'outpath'."
4.78 +
4.79 + if isfile(pathname):
4.80 + outdir = split(outpath)[0]
4.81 + if outdir and not exists(outdir):
4.82 + makedirs(outdir)
4.83 + copy(pathname, outpath)
4.84 + else:
4.85 + if not exists(outpath):
4.86 + makedirs(outpath)
4.87 + for filename in listdir(pathname):
4.88 + self.copy(join(pathname, filename), join(outpath, filename))
4.89 +
4.90 + def load_resource(self, filename):
4.91 +
4.92 + "Return the textual content of the resource with the given 'filename'."
4.93 +
4.94 + f = open(self.get_resource(filename))
4.95 + try:
4.96 + return f.read()
4.97 + finally:
4.98 + f.close()
4.99 +
4.100 +# vim: tabstop=4 expandtab shiftwidth=4
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/moinformat/themes/default/__init__.py Mon Aug 13 17:55:16 2018 +0200
5.3 @@ -0,0 +1,22 @@
5.4 +#!/usr/bin/env python
5.5 +
5.6 +"""
5.7 +A default theme.
5.8 +
5.9 +Copyright (C) 2018 Paul Boddie <paul@boddie.org.uk>
5.10 +
5.11 +This program is free software; you can redistribute it and/or modify it under
5.12 +the terms of the GNU General Public License as published by the Free Software
5.13 +Foundation; either version 3 of the License, or (at your option) any later
5.14 +version.
5.15 +
5.16 +This program is distributed in the hope that it will be useful, but WITHOUT
5.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
5.18 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
5.19 +details.
5.20 +
5.21 +You should have received a copy of the GNU General Public License along with
5.22 +this program. If not, see <http://www.gnu.org/licenses/>.
5.23 +"""
5.24 +
5.25 +# vim: tabstop=4 expandtab shiftwidth=4
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/moinformat/themes/default/css/common.css Mon Aug 13 17:55:16 2018 +0200
6.3 @@ -0,0 +1,9 @@
6.4 +table {
6.5 + border-collapse: collapse;
6.6 + margin: 0.5em 0 0.5em 0;
6.7 +}
6.8 +
6.9 +table td {
6.10 + border: 1px solid #000;
6.11 + padding: 0.5em;
6.12 +}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/moinformat/themes/default/html.py Mon Aug 13 17:55:16 2018 +0200
7.3 @@ -0,0 +1,52 @@
7.4 +#!/usr/bin/env python
7.5 +
7.6 +"""
7.7 +A default theme for HTML output.
7.8 +
7.9 +Copyright (C) 2018 Paul Boddie <paul@boddie.org.uk>
7.10 +
7.11 +This program is free software; you can redistribute it and/or modify it under
7.12 +the terms of the GNU General Public License as published by the Free Software
7.13 +Foundation; either version 3 of the License, or (at your option) any later
7.14 +version.
7.15 +
7.16 +This program is distributed in the hope that it will be useful, but WITHOUT
7.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
7.18 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
7.19 +details.
7.20 +
7.21 +You should have received a copy of the GNU General Public License along with
7.22 +this program. If not, see <http://www.gnu.org/licenses/>.
7.23 +"""
7.24 +
7.25 +from moinformat.themes.common import Theme
7.26 +
7.27 +class DefaultHTMLTheme(Theme):
7.28 +
7.29 + "A default theme."
7.30 +
7.31 + name = "html"
7.32 + origin = __file__
7.33 +
7.34 + def apply(self, text):
7.35 +
7.36 + "Apply this theme to the given 'text', returning a themed version."
7.37 +
7.38 + template = self.load_resource("template.html")
7.39 + subs = {
7.40 + "encoding" : self.output.encoding,
7.41 + "root" : self.linker.get_top_level() or ".",
7.42 + "text" : text,
7.43 + "title" : self.pagename,
7.44 + }
7.45 + return template % subs
7.46 +
7.47 + def install_resources(self):
7.48 +
7.49 + "Install resources for this theme."
7.50 +
7.51 + self.install_resource("css", "_css")
7.52 +
7.53 +theme = DefaultHTMLTheme
7.54 +
7.55 +# vim: tabstop=4 expandtab shiftwidth=4
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/moinformat/themes/default/template.html Mon Aug 13 17:55:16 2018 +0200
8.3 @@ -0,0 +1,11 @@
8.4 +<!DOCTYPE html>
8.5 +<html>
8.6 +<head>
8.7 +<title>%(title)s</title>
8.8 +<link rel="stylesheet" type="text/css" charset="utf-8" media="all" href="%(root)s/_css/common.css" />
8.9 +<meta http-equiv="Content-Type" content="text/html;charset=%(encoding)s" />
8.10 +</head>
8.11 +<body>
8.12 +%(text)s
8.13 +</body>
8.14 +</html>
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/moinformat/themes/manifest.py Mon Aug 13 17:55:16 2018 +0200
9.3 @@ -0,0 +1,35 @@
9.4 +#!/usr/bin/env python
9.5 +
9.6 +"""
9.7 +Theme implementation manifest.
9.8 +
9.9 +Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk>
9.10 +
9.11 +This program is free software; you can redistribute it and/or modify it under
9.12 +the terms of the GNU General Public License as published by the Free Software
9.13 +Foundation; either version 3 of the License, or (at your option) any later
9.14 +version.
9.15 +
9.16 +This program is distributed in the hope that it will be useful, but WITHOUT
9.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9.18 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
9.19 +details.
9.20 +
9.21 +You should have received a copy of the GNU General Public License along with
9.22 +this program. If not, see <http://www.gnu.org/licenses/>.
9.23 +"""
9.24 +
9.25 +from moinformat.imports import get_extensions, get_mapping, get_modules
9.26 +
9.27 +# Define an attribute mapping names to modules.
9.28 +
9.29 +modules = get_modules(__file__, __name__)
9.30 +
9.31 +# Obtain all themes.
9.32 +
9.33 +# Use module paths to register the contexts:
9.34 +# theme_name.output_format -> theme
9.35 +
9.36 +themes = get_mapping(modules, lambda n, m: n, lambda m: m.theme)
9.37 +
9.38 +# vim: tabstop=4 expandtab shiftwidth=4