Server : Apache System : Linux iad1-shared-b8-43 6.6.49-grsec-jammy+ #10 SMP Thu Sep 12 23:23:08 UTC 2024 x86_64 User : dh_edsupp ( 6597262) PHP Version : 8.2.26 Disable Function : NONE Directory : /lib/python3/dist-packages/trac/mimeview/ |
Upload File : |
# -*- coding: utf-8 -*- # # Copyright (C) 2004-2021 Edgewall Software # Copyright (C) 2004 Oliver Rutherfurd # All rights reserved. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://trac.edgewall.org/wiki/TracLicense. # # This software consists of voluntary contributions made by many # individuals. For the exact contribution history, see the revision # history and logs, available at https://trac.edgewall.org/log/. # # Author: Daniel Lundin # Oliver Rutherfurd (initial implementation) # Nuutti Kotivuori (role support) # # Trac support for reStructured Text, including a custom 'trac' directive # # 'trac' directive code by Oliver Rutherfurd, overhauled by cboos. # # Inserts `reference` nodes for TracLinks into the document tree. __docformat__ = 'reStructuredText' try: from docutils import nodes from docutils.core import publish_parts from docutils.parsers import rst from docutils.readers import standalone from docutils.writers import html4css1 from docutils import __version__ except ImportError: has_docutils = False else: has_docutils = True from trac.api import ISystemInfoProvider from trac.core import * from trac.mimeview.api import IHTMLPreviewRenderer, content_to_unicode from trac.util.html import Element, Fragment, Markup, escape, find_element from trac.util.translation import _ from trac.wiki.api import WikiSystem from trac.wiki.formatter import WikiProcessor, Formatter, extract_link if has_docutils: # Register "trac" role handler and directive def trac_get_reference(env, context, rawtext, target, text): fulltext = target + ' ' + text if text else target link = extract_link(env, context, fulltext) uri = None missing = False if isinstance(link, (Element, Fragment)): linktext = Markup(link).striptags() # the following is a bit hackish, but it takes into account: # - an eventual trailing '?' for missing wiki pages # - space eventually introduced due to split_page_names option if linktext.rstrip('?').replace(' ', '') != target: text = linktext elt = find_element(link, 'href', 'missing') if elt is not None: uri = elt.attrib.get('href', '') missing = 'missing' in elt.attrib.get('class', '').split() else: uri = context.href.wiki(target) missing = not WikiSystem(env).has_page(target) if uri or missing: reference = nodes.reference(rawtext, text or target) reference['refuri'] = uri if missing: reference['classes'].append('missing') return reference def trac_directive(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine): """Inserts a `reference` node into the document for a given `TracLink`_, based on the content of the arguments. Usage:: .. trac:: target [text] ``target`` may be any `TracLink`_, provided it doesn't embed a space character (e.g. wiki:"..." notation won't work). ``[text]`` is optional. If not given, ``target`` is used as the reference text. .. _TracLink: https://trac.edgewall.org/wiki/TracLinks """ if hasattr(state.inliner, 'trac'): env, context = state.inliner.trac link = arguments[0] if len(arguments) == 2: text = arguments[1] else: text = None reference = trac_get_reference(env, context, block_text, link, text) if reference: if isinstance(state, rst.states.SubstitutionDef): return [reference] p = nodes.paragraph() p += reference return [p] # didn't find a match (invalid TracLink) msg = _("%(link)s is not a valid TracLink", link=arguments[0]) # this is an user facing message, hence localized else: msg = "No trac context active while rendering" # this is more an internal error, not translated. # report a warning warning = state_machine.reporter.warning( msg, nodes.literal_block(block_text, block_text), line=lineno) return [warning] def trac_role(name, rawtext, text, lineno, inliner, options={}, content=[]): if hasattr(inliner, 'trac'): env, context = inliner.trac args = text.split(" ", 1) link = args[0] if len(args) == 2: text = args[1] else: text = None reference = trac_get_reference(env, context, rawtext, link, text) if reference: return [reference], [] msg = _("%(link)s is not a valid TracLink", link=rawtext) else: msg = "No trac context active while rendering" return nodes.warning(None, nodes.literal_block(text, msg)), [] # 1 required arg, 1 optional arg, spaces allowed in last arg trac_directive.arguments = (1, 1, 1) trac_directive.options = None trac_directive.content = None rst.directives.register_directive('trac', trac_directive) rst.roles.register_canonical_role('trac', trac_role) # Register "code-block" role handler and directive # (code derived from the leo plugin rst2) def code_formatter(env, context, language, text): processor = WikiProcessor(Formatter(env, context), language) html = processor.process(text) raw = nodes.raw('', html, format='html') return raw def code_block_role(name, rawtext, text, lineno, inliner, options={}, content=[]): if not hasattr(inliner, 'trac'): return [], [] env, context = inliner.trac language = options.get('language') if not language: args = text.split(':', 1) language = args[0] if len(args) == 2: text = args[1] else: text = '' return [code_formatter(env, context, language, text)], [] def code_block_directive(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine): """ Create a code-block directive for docutils. Usage: .. code-block:: language If the language can be syntax highlighted it will be. """ if not hasattr(state.inliner, 'trac'): return [] env, context = state.inliner.trac language = arguments[0] text = '\n'.join(content) return [code_formatter(env, context, language, text)] # These are documented # at http://docutils.sourceforge.net/spec/howto/rst-directives.html. code_block_directive.arguments = ( 1, # Number of required arguments. 0, # Number of optional arguments. 0) # True if final argument may contain whitespace. # A mapping from option name to conversion function. code_block_role.options = code_block_directive.options = { 'language': rst.directives.unchanged # Return the text argument, unchanged } code_block_directive.content = 1 # True if content is allowed. # Register the directive with docutils. rst.directives.register_directive('code-block', code_block_directive) rst.roles.register_local_role('code-block', code_block_role) class ReStructuredTextRenderer(Component): """HTML renderer for plain text in reStructuredText format.""" implements(IHTMLPreviewRenderer, ISystemInfoProvider) # ISystemInfoProvider methods def get_system_info(self): if has_docutils: yield 'Docutils', __version__ # IHTMLPreviewRenderer methods def get_quality_ratio(self, mimetype): if has_docutils and \ mimetype in ('text/x-rst', 'text/prs.fallenstein.rst'): return 8 return 0 def render(self, context, mimetype, content, filename=None, rev=None): # Minimize visual impact of errors class TracHTMLTranslator(html4css1.HTMLTranslator): """Specialized translator with unobtrusive error reporting and some extra security features. """ def __init__(self, *args, **kwargs): self._render_unsafe_content = wikisys.render_unsafe_content self._safe_schemes = set(wikisys.safe_schemes) html4css1.HTMLTranslator.__init__(self, *args, **kwargs) def visit_system_message(self, node): paragraph = node.children.pop(0) message = escape(paragraph.astext()) if paragraph else '' backrefs = node['backrefs'] if backrefs: span = ('<span class="system-message">%s</span>' % (''.join('<a href="#%s" title="%s">?</a>' % (backref, message) for backref in backrefs))) else: span = ('<span class="system-message" title="%s">?</span>' % message) self.body.append(span) def depart_system_message(self, node): pass def visit_image(self, node): html4css1.HTMLTranslator.visit_image(self, node) uri = node.attributes.get('uri') if not wikisys.is_safe_origin(uri, context.req): self.body[-1] = self.body[-1].replace( '<img ', '<img crossorigin="anonymous" ') def visit_reference(self, node): if self._is_safe_uri(node.get('refuri')): html4css1.HTMLTranslator.visit_reference(self, node) def depart_reference(self, node): if self._is_safe_uri(node.get('refuri')): html4css1.HTMLTranslator.depart_reference(self, node) def _is_safe_uri(self, uri): if self._render_unsafe_content or not uri: return True else: pos = uri.find(':') return pos < 0 or uri[0:pos] in self._safe_schemes wikisys = WikiSystem(self.env) writer = html4css1.Writer() writer.translator_class = TracHTMLTranslator inliner = rst.states.Inliner() inliner.trac = (self.env, context) parser = rst.Parser(inliner=inliner) content = content_to_unicode(self.env, content, mimetype) # The default Reader is explicitly passed as a workaround for #11248 parts = publish_parts(content, writer=writer, parser=parser, reader=standalone.Reader(parser), settings_overrides={'halt_level': 6, 'file_insertion_enabled': 0, 'raw_enabled': 0, 'warning_stream': False}) return parts['html_body']