summaryrefslogtreecommitdiff
path: root/.config/qutebrowser/scripts/asciidoc2html.py
diff options
context:
space:
mode:
Diffstat (limited to '.config/qutebrowser/scripts/asciidoc2html.py')
-rwxr-xr-x.config/qutebrowser/scripts/asciidoc2html.py303
1 files changed, 303 insertions, 0 deletions
diff --git a/.config/qutebrowser/scripts/asciidoc2html.py b/.config/qutebrowser/scripts/asciidoc2html.py
new file mode 100755
index 0000000..c4af174
--- /dev/null
+++ b/.config/qutebrowser/scripts/asciidoc2html.py
@@ -0,0 +1,303 @@
+#!/usr/bin/env python3
+# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
+
+# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+
+# This file is part of qutebrowser.
+#
+# qutebrowser 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.
+#
+# qutebrowser 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 qutebrowser. If not, see <http://www.gnu.org/licenses/>.
+
+"""Generate the html documentation based on the asciidoc files."""
+
+import re
+import os
+import os.path
+import sys
+import subprocess
+import glob
+import shutil
+import tempfile
+import argparse
+import io
+
+sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.pardir))
+
+from scripts import utils
+
+
+class AsciiDoc:
+
+ """Abstraction of an asciidoc subprocess."""
+
+ FILES = ['faq', 'changelog', 'contributing', 'quickstart', 'userscripts']
+
+ def __init__(self, args):
+ self._cmd = None
+ self._args = args
+ self._homedir = None
+ self._themedir = None
+ self._tempdir = None
+ self._failed = False
+
+ def prepare(self):
+ """Get the asciidoc command and create the homedir to use."""
+ self._cmd = self._get_asciidoc_cmd()
+ self._homedir = tempfile.mkdtemp()
+ self._themedir = os.path.join(
+ self._homedir, '.asciidoc', 'themes', 'qute')
+ self._tempdir = os.path.join(self._homedir, 'tmp')
+ os.makedirs(self._tempdir)
+ os.makedirs(self._themedir)
+
+ def cleanup(self):
+ """Clean up the temporary home directory for asciidoc."""
+ if self._homedir is not None and not self._failed:
+ shutil.rmtree(self._homedir)
+
+ def build(self):
+ """Build either the website or the docs."""
+ if self._args.website:
+ self._build_website()
+ else:
+ self._build_docs()
+ self._copy_images()
+
+ def _build_docs(self):
+ """Render .asciidoc files to .html sites."""
+ files = [('doc/{}.asciidoc'.format(f),
+ 'qutebrowser/html/doc/{}.html'.format(f))
+ for f in self.FILES]
+ for src in glob.glob('doc/help/*.asciidoc'):
+ name, _ext = os.path.splitext(os.path.basename(src))
+ dst = 'qutebrowser/html/doc/{}.html'.format(name)
+ files.append((src, dst))
+
+ # patch image links to use local copy
+ replacements = [
+ ("https://raw.githubusercontent.com/qutebrowser/qutebrowser/master/doc/img/cheatsheet-big.png",
+ "qute://help/img/cheatsheet-big.png"),
+ ("https://raw.githubusercontent.com/qutebrowser/qutebrowser/master/doc/img/cheatsheet-small.png",
+ "qute://help/img/cheatsheet-small.png")
+ ]
+ asciidoc_args = ['-a', 'source-highlighter=pygments']
+
+ for src, dst in files:
+ src_basename = os.path.basename(src)
+ modified_src = os.path.join(self._tempdir, src_basename)
+ with open(modified_src, 'w', encoding='utf-8') as modified_f, \
+ open(src, 'r', encoding='utf-8') as f:
+ for line in f:
+ for orig, repl in replacements:
+ line = line.replace(orig, repl)
+ modified_f.write(line)
+ self.call(modified_src, dst, *asciidoc_args)
+
+ def _copy_images(self):
+ """Copy image files to qutebrowser/html/doc."""
+ print("Copying files...")
+ dst_path = os.path.join('qutebrowser', 'html', 'doc', 'img')
+ try:
+ os.mkdir(dst_path)
+ except FileExistsError:
+ pass
+ for filename in ['cheatsheet-big.png', 'cheatsheet-small.png']:
+ src = os.path.join('doc', 'img', filename)
+ dst = os.path.join(dst_path, filename)
+ shutil.copy(src, dst)
+
+ def _build_website_file(self, root, filename):
+ """Build a single website file."""
+ src = os.path.join(root, filename)
+ src_basename = os.path.basename(src)
+ parts = [self._args.website[0]]
+ dirname = os.path.dirname(src)
+ if dirname:
+ parts.append(os.path.relpath(os.path.dirname(src)))
+ parts.append(
+ os.extsep.join((os.path.splitext(src_basename)[0],
+ 'html')))
+ dst = os.path.join(*parts)
+ os.makedirs(os.path.dirname(dst), exist_ok=True)
+
+ modified_src = os.path.join(self._tempdir, src_basename)
+ shutil.copy('www/header.asciidoc', modified_src)
+
+ outfp = io.StringIO()
+
+ with open(modified_src, 'r', encoding='utf-8') as header_file:
+ header = header_file.read()
+ header += "\n\n"
+
+ with open(src, 'r', encoding='utf-8') as infp:
+ outfp.write("\n\n")
+ hidden = False
+ found_title = False
+ title = ""
+ last_line = ""
+
+ for line in infp:
+ line = line.rstrip()
+ if line == '// QUTE_WEB_HIDE':
+ assert not hidden
+ hidden = True
+ elif line == '// QUTE_WEB_HIDE_END':
+ assert hidden
+ hidden = False
+ elif line == "The Compiler <mail@qutebrowser.org>":
+ continue
+ elif re.fullmatch(r':\w+:.*', line):
+ # asciidoc field
+ continue
+
+ if not found_title:
+ if re.fullmatch(r'=+', line):
+ line = line.replace('=', '-')
+ found_title = True
+ title = last_line + " | qutebrowser\n"
+ title += "=" * (len(title) - 1)
+ elif re.fullmatch(r'= .+', line):
+ line = '==' + line[1:]
+ found_title = True
+ title = last_line + " | qutebrowser\n"
+ title += "=" * (len(title) - 1)
+
+ if not hidden:
+ outfp.write(line.replace(".asciidoc[", ".html[") + '\n')
+ last_line = line
+
+ current_lines = outfp.getvalue()
+ outfp.close()
+
+ with open(modified_src, 'w+', encoding='utf-8') as final_version:
+ final_version.write(title + "\n\n" + header + current_lines)
+
+ asciidoc_args = ['--theme=qute', '-a toc', '-a toc-placement=manual',
+ '-a', 'source-highlighter=pygments']
+ self.call(modified_src, dst, *asciidoc_args)
+
+ def _build_website(self):
+ """Prepare and build the website."""
+ theme_file = os.path.abspath(os.path.join('www', 'qute.css'))
+ shutil.copy(theme_file, self._themedir)
+
+ outdir = self._args.website[0]
+
+ for root, _dirs, files in os.walk(os.getcwd()):
+ for filename in files:
+ basename, ext = os.path.splitext(filename)
+ if (ext != '.asciidoc' or
+ basename in ['header', 'OpenSans-License']):
+ continue
+ self._build_website_file(root, filename)
+
+ copy = {'icons': 'icons', 'doc/img': 'doc/img', 'www/media': 'media/'}
+
+ for src, dest in copy.items():
+ full_dest = os.path.join(outdir, dest)
+ try:
+ shutil.rmtree(full_dest)
+ except FileNotFoundError:
+ pass
+ shutil.copytree(src, full_dest)
+
+ for dst, link_name in [
+ ('README.html', 'index.html'),
+ (os.path.join('doc', 'quickstart.html'), 'quickstart.html')]:
+ try:
+ os.symlink(dst, os.path.join(outdir, link_name))
+ except FileExistsError:
+ pass
+
+ def _get_asciidoc_cmd(self):
+ """Try to find out what commandline to use to invoke asciidoc."""
+ if self._args.asciidoc is not None:
+ return self._args.asciidoc
+
+ try:
+ subprocess.run(['asciidoc'], stdout=subprocess.DEVNULL,
+ stderr=subprocess.DEVNULL)
+ except OSError:
+ pass
+ else:
+ return ['asciidoc']
+
+ try:
+ subprocess.run(['asciidoc.py'], stdout=subprocess.DEVNULL,
+ stderr=subprocess.DEVNULL)
+ except OSError:
+ pass
+ else:
+ return ['asciidoc.py']
+
+ raise FileNotFoundError
+
+ def call(self, src, dst, *args):
+ """Call asciidoc for the given files.
+
+ Args:
+ src: The source .asciidoc file.
+ dst: The destination .html file, or None to auto-guess.
+ *args: Additional arguments passed to asciidoc.
+ """
+ print("Calling asciidoc for {}...".format(os.path.basename(src)))
+ cmdline = self._cmd[:]
+ if dst is not None:
+ cmdline += ['--out-file', dst]
+ cmdline += args
+ cmdline.append(src)
+ try:
+ env = os.environ.copy()
+ env['HOME'] = self._homedir
+ subprocess.run(cmdline, check=True, env=env)
+ except (subprocess.CalledProcessError, OSError) as e:
+ self._failed = True
+ utils.print_col(str(e), 'red')
+ print("Keeping modified sources in {}.".format(self._homedir))
+ sys.exit(1)
+
+
+def main(colors=False):
+ """Generate html files for the online documentation."""
+ utils.change_cwd()
+ utils.use_color = colors
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--website', help="Build website into a given "
+ "directory.", nargs=1)
+ parser.add_argument('--asciidoc', help="Full path to python and "
+ "asciidoc.py. If not given, it's searched in PATH.",
+ nargs=2, required=False,
+ metavar=('PYTHON', 'ASCIIDOC'))
+ args = parser.parse_args()
+ try:
+ os.mkdir('qutebrowser/html/doc')
+ except FileExistsError:
+ pass
+
+ asciidoc = AsciiDoc(args)
+ try:
+ asciidoc.prepare()
+ except FileNotFoundError:
+ utils.print_col("Could not find asciidoc! Please install it, or use "
+ "the --asciidoc argument to point this script to the "
+ "correct python/asciidoc.py location!", 'red')
+ sys.exit(1)
+
+ try:
+ asciidoc.build()
+ finally:
+ asciidoc.cleanup()
+
+
+if __name__ == '__main__':
+ main(colors=True)