aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/docutils/writers/s5_html/__init__.py
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/docutils/writers/s5_html/__init__.py
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are hereHEADmaster
Diffstat (limited to '.venv/lib/python3.12/site-packages/docutils/writers/s5_html/__init__.py')
-rw-r--r--.venv/lib/python3.12/site-packages/docutils/writers/s5_html/__init__.py353
1 files changed, 353 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/docutils/writers/s5_html/__init__.py b/.venv/lib/python3.12/site-packages/docutils/writers/s5_html/__init__.py
new file mode 100644
index 00000000..7014de33
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/docutils/writers/s5_html/__init__.py
@@ -0,0 +1,353 @@
+# $Id: __init__.py 9542 2024-02-17 10:37:23Z milde $
+# Authors: Chris Liechti <cliechti@gmx.net>;
+# David Goodger <goodger@python.org>
+# Copyright: This module has been placed in the public domain.
+
+"""
+S5/HTML Slideshow Writer.
+"""
+
+__docformat__ = 'reStructuredText'
+
+import sys
+import os
+import re
+import docutils
+from docutils import frontend, nodes, utils
+from docutils.writers import html4css1
+
+themes_dir_path = utils.relative_path(
+ os.path.join(os.getcwd(), 'dummy'),
+ os.path.join(os.path.dirname(__file__), 'themes'))
+
+
+def find_theme(name):
+ # Where else to look for a theme?
+ # Check working dir? Destination dir? Config dir? Plugins dir?
+ path = os.path.join(themes_dir_path, name)
+ if not os.path.isdir(path):
+ raise docutils.ApplicationError(
+ 'Theme directory not found: %r (path: %r)' % (name, path))
+ return path
+
+
+class Writer(html4css1.Writer):
+
+ settings_spec = html4css1.Writer.settings_spec + (
+ 'S5 Slideshow Specific Options',
+ 'For the S5/HTML writer, the --no-toc-backlinks option '
+ '(defined in General Docutils Options above) is the default, '
+ 'and should not be changed.',
+ (('Specify an installed S5 theme by name. Overrides --theme-url. '
+ 'The default theme name is "default". The theme files will be '
+ 'copied into a "ui/<theme>" directory, in the same directory as the '
+ 'destination file (output HTML). Note that existing theme files '
+ 'will not be overwritten (unless --overwrite-theme-files is used).',
+ ['--theme'],
+ {'default': 'default', 'metavar': '<name>',
+ 'overrides': 'theme_url'}),
+ ('Specify an S5 theme URL. The destination file (output HTML) will '
+ 'link to this theme; nothing will be copied. Overrides --theme.',
+ ['--theme-url'],
+ {'metavar': '<URL>', 'overrides': 'theme'}),
+ ('Allow existing theme files in the ``ui/<theme>`` directory to be '
+ 'overwritten. The default is not to overwrite theme files.',
+ ['--overwrite-theme-files'],
+ {'action': 'store_true', 'validator': frontend.validate_boolean}),
+ ('Keep existing theme files in the ``ui/<theme>`` directory; do not '
+ 'overwrite any. This is the default.',
+ ['--keep-theme-files'],
+ {'dest': 'overwrite_theme_files', 'action': 'store_false'}),
+ ('Set the initial view mode to "slideshow" [default] or "outline".',
+ ['--view-mode'],
+ {'choices': ['slideshow', 'outline'], 'default': 'slideshow',
+ 'metavar': '<mode>'}),
+ ('Normally hide the presentation controls in slideshow mode. '
+ 'This is the default.',
+ ['--hidden-controls'],
+ {'action': 'store_true', 'default': True,
+ 'validator': frontend.validate_boolean}),
+ ('Always show the presentation controls in slideshow mode. '
+ 'The default is to hide the controls.',
+ ['--visible-controls'],
+ {'dest': 'hidden_controls', 'action': 'store_false'}),
+ ('Enable the current slide indicator ("1 / 15"). '
+ 'The default is to disable it.',
+ ['--current-slide'],
+ {'action': 'store_true', 'validator': frontend.validate_boolean}),
+ ('Disable the current slide indicator. This is the default.',
+ ['--no-current-slide'],
+ {'dest': 'current_slide', 'action': 'store_false'}),))
+
+ settings_default_overrides = {'toc_backlinks': 0}
+
+ config_section = 's5_html writer'
+ config_section_dependencies = ('writers', 'html writers',
+ 'html4css1 writer')
+
+ def __init__(self):
+ html4css1.Writer.__init__(self)
+ self.translator_class = S5HTMLTranslator
+
+
+class S5HTMLTranslator(html4css1.HTMLTranslator):
+
+ s5_stylesheet_template = """\
+<!-- configuration parameters -->
+<meta name="defaultView" content="%(view_mode)s" />
+<meta name="controlVis" content="%(control_visibility)s" />
+<!-- style sheet links -->
+<script src="%(path)s/slides.js" type="text/javascript"></script>
+<link rel="stylesheet" href="%(path)s/slides.css"
+ type="text/css" media="projection" id="slideProj" />
+<link rel="stylesheet" href="%(path)s/outline.css"
+ type="text/css" media="screen" id="outlineStyle" />
+<link rel="stylesheet" href="%(path)s/print.css"
+ type="text/css" media="print" id="slidePrint" />
+<link rel="stylesheet" href="%(path)s/opera.css"
+ type="text/css" media="projection" id="operaFix" />\n"""
+ # The script element must go in front of the link elements to
+ # avoid a flash of unstyled content (FOUC), reproducible with
+ # Firefox.
+
+ disable_current_slide = """
+<style type="text/css">
+#currentSlide {display: none;}
+</style>\n"""
+
+ layout_template = """\
+<div class="layout">
+<div id="controls"></div>
+<div id="currentSlide"></div>
+<div id="header">
+%(header)s
+</div>
+<div id="footer">
+%(title)s%(footer)s
+</div>
+</div>\n"""
+# <div class="topleft"></div>
+# <div class="topright"></div>
+# <div class="bottomleft"></div>
+# <div class="bottomright"></div>
+
+ default_theme = 'default'
+ """Name of the default theme."""
+
+ base_theme_file = '__base__'
+ """Name of the file containing the name of the base theme."""
+
+ direct_theme_files = (
+ 'slides.css', 'outline.css', 'print.css', 'opera.css', 'slides.js')
+ """Names of theme files directly linked to in the output HTML"""
+
+ indirect_theme_files = (
+ 's5-core.css', 'framing.css', 'pretty.css')
+ """Names of files used indirectly; imported or used by files in
+ `direct_theme_files`."""
+
+ required_theme_files = indirect_theme_files + direct_theme_files
+ """Names of mandatory theme files."""
+
+ def __init__(self, *args):
+ html4css1.HTMLTranslator.__init__(self, *args)
+ # insert S5-specific stylesheet and script stuff:
+ self.theme_file_path = None
+ try:
+ self.setup_theme()
+ except docutils.ApplicationError as e:
+ self.document.reporter.warning(e)
+ view_mode = self.document.settings.view_mode
+ control_visibility = ('visible', 'hidden')[self.document.settings
+ .hidden_controls]
+ self.stylesheet.append(self.s5_stylesheet_template
+ % {'path': self.theme_file_path,
+ 'view_mode': view_mode,
+ 'control_visibility': control_visibility})
+ if not self.document.settings.current_slide:
+ self.stylesheet.append(self.disable_current_slide)
+ self.meta.append('<meta name="version" content="S5 1.1" />\n')
+ self.s5_footer = []
+ self.s5_header = []
+ self.section_count = 0
+ self.theme_files_copied = None
+
+ def setup_theme(self):
+ if self.document.settings.theme:
+ self.copy_theme()
+ elif self.document.settings.theme_url:
+ self.theme_file_path = self.document.settings.theme_url
+ else:
+ raise docutils.ApplicationError(
+ 'No theme specified for S5/HTML writer.')
+
+ def copy_theme(self):
+ """
+ Locate & copy theme files.
+
+ A theme may be explicitly based on another theme via a '__base__'
+ file. The default base theme is 'default'. Files are accumulated
+ from the specified theme, any base themes, and 'default'.
+ """
+ settings = self.document.settings
+ path = find_theme(settings.theme)
+ theme_paths = [path]
+ self.theme_files_copied = {}
+ required_files_copied = {}
+ # This is a link (URL) in HTML, so we use "/", not os.sep:
+ self.theme_file_path = 'ui/%s' % settings.theme
+ if not settings.output:
+ raise docutils.ApplicationError(
+ 'Output path not specified, you may need to copy'
+ ' the S5 theme files "by hand" or set the "--output" option.')
+ dest = os.path.join(
+ os.path.dirname(settings.output), 'ui', settings.theme)
+ if not os.path.isdir(dest):
+ os.makedirs(dest)
+ default = False
+ while path:
+ for f in os.listdir(path): # copy all files from each theme
+ if f == self.base_theme_file:
+ continue # ... except the "__base__" file
+ if (self.copy_file(f, path, dest)
+ and f in self.required_theme_files):
+ required_files_copied[f] = True
+ if default:
+ break # "default" theme has no base theme
+ # Find the "__base__" file in theme directory:
+ base_theme_file = os.path.join(path, self.base_theme_file)
+ # If it exists, read it and record the theme path:
+ if os.path.isfile(base_theme_file):
+ with open(base_theme_file, encoding='utf-8') as f:
+ lines = f.readlines()
+ for line in lines:
+ line = line.strip()
+ if line and not line.startswith('#'):
+ path = find_theme(line)
+ if path in theme_paths: # check for duplicates/cycles
+ path = None # if found, use default base
+ else:
+ theme_paths.append(path)
+ break
+ else: # no theme name found
+ path = None # use default base
+ else: # no base theme file found
+ path = None # use default base
+ if not path:
+ path = find_theme(self.default_theme)
+ theme_paths.append(path)
+ default = True
+ if len(required_files_copied) != len(self.required_theme_files):
+ # Some required files weren't found & couldn't be copied.
+ required = list(self.required_theme_files)
+ for f in required_files_copied.keys():
+ required.remove(f)
+ raise docutils.ApplicationError(
+ 'Theme files not found: %s'
+ % ', '.join('%r' % f for f in required))
+
+ files_to_skip_pattern = re.compile(r'~$|\.bak$|#$|\.cvsignore$')
+
+ def copy_file(self, name, source_dir, dest_dir):
+ """
+ Copy file `name` from `source_dir` to `dest_dir`.
+ Return True if the file exists in either `source_dir` or `dest_dir`.
+ """
+ source = os.path.join(source_dir, name)
+ dest = os.path.join(dest_dir, name)
+ if dest in self.theme_files_copied:
+ return True
+ else:
+ self.theme_files_copied[dest] = True
+ if os.path.isfile(source):
+ if self.files_to_skip_pattern.search(source):
+ return None
+ settings = self.document.settings
+ if os.path.exists(dest) and not settings.overwrite_theme_files:
+ settings.record_dependencies.add(dest)
+ else:
+ with open(source, 'rb') as src_file:
+ src_data = src_file.read()
+ with open(dest, 'wb') as dest_file:
+ dest_dir = dest_dir.replace(os.sep, '/')
+ dest_file.write(src_data.replace(
+ b'ui/default',
+ dest_dir[dest_dir.rfind('ui/'):].encode(
+ sys.getfilesystemencoding())))
+ settings.record_dependencies.add(source)
+ return True
+ if os.path.isfile(dest):
+ return True
+
+ def depart_document(self, node):
+ self.head_prefix.extend([self.doctype,
+ self.head_prefix_template %
+ {'lang': self.settings.language_code}])
+ self.html_prolog.append(self.doctype)
+ self.head = self.meta[:] + self.head
+ if self.math_header:
+ if self.math_output == 'mathjax':
+ self.head.extend(self.math_header)
+ else:
+ self.stylesheet.extend(self.math_header)
+ # skip content-type meta tag with interpolated charset value:
+ self.html_head.extend(self.head[1:])
+ self.fragment.extend(self.body)
+ # special S5 code up to the next comment line
+ header = ''.join(self.s5_header)
+ footer = ''.join(self.s5_footer)
+ title = ''.join(self.html_title).replace('<h1 class="title">', '<h1>')
+ layout = self.layout_template % {'header': header,
+ 'title': title,
+ 'footer': footer}
+ self.body_prefix.extend(layout)
+ self.body_prefix.append('<div class="presentation">\n')
+ self.body_prefix.append(
+ self.starttag({'classes': ['slide'], 'ids': ['slide0']}, 'div'))
+ if not self.section_count:
+ self.body.append('</div>\n')
+ #
+ self.body_suffix.insert(0, '</div>\n')
+ self.html_body.extend(self.body_prefix[1:] + self.body_pre_docinfo
+ + self.docinfo + self.body
+ + self.body_suffix[:-1])
+
+ def depart_footer(self, node):
+ start = self.context.pop()
+ self.s5_footer.append('<h2>')
+ self.s5_footer.extend(self.body[start:])
+ self.s5_footer.append('</h2>')
+ del self.body[start:]
+
+ def depart_header(self, node):
+ start = self.context.pop()
+ header = ['<div id="header">\n']
+ header.extend(self.body[start:])
+ header.append('\n</div>\n')
+ del self.body[start:]
+ self.s5_header.extend(header)
+
+ def visit_section(self, node):
+ if not self.section_count:
+ self.body.append('\n</div>\n')
+ self.section_count += 1
+ self.section_level += 1
+ if self.section_level > 1:
+ # dummy for matching div's
+ self.body.append(self.starttag(node, 'div', CLASS='section'))
+ else:
+ self.body.append(self.starttag(node, 'div', CLASS='slide'))
+
+ def visit_subtitle(self, node):
+ if isinstance(node.parent, nodes.section):
+ level = self.section_level + self.initial_header_level - 1
+ if level == 1:
+ level = 2
+ tag = 'h%s' % level
+ self.body.append(self.starttag(node, tag, ''))
+ self.context.append('</%s>\n' % tag)
+ else:
+ html4css1.HTMLTranslator.visit_subtitle(self, node)
+
+ def visit_title(self, node):
+ html4css1.HTMLTranslator.visit_title(self, node)