def slink_role(role, rawtext, text, lineno, inliner, options={}, content=[]): def warn(err): msg = "\n error in %s\n %s"%(rawtext,err) inliner.reporter.warning(msg,line=lineno) try: text = text%app.config.slink_vars except Exception as exc: #err = traceback.format_exc(0).strip() err = traceback.format_exception_only(exc.__class__, exc)[0] warn(err.strip()) lidx,ridx = text.find('<'), text.find('>') if lidx >= 0 and ridx > lidx and ridx == len(text)-1: ref = text[lidx+1:ridx] name = utils.unescape(text[:lidx].strip()) elif lidx > 0 or ridx > 0: warn('Incorrect reference format in expanded link: '+text) ref = '' name = utils.unescape(text) else: ref = text name = utils.unescape(ref) node = nodes.reference(rawtext, name, refuri=ref, **options) return [node], []
def wikilink (self, match, lineno) : text = match.group (0)[1:-1] ref = self.root + text unescaped = unescape (text, 0) r = nodes.reference (unescape (text, 1), unescaped, refuri = ref) r["classes"].append ("wikiname") return [r]
def code(role, rawtext, text, lineno, inliner, options={}, content=[]): # In order to properly preserve backslashes i = rawtext.find('`') text = rawtext.split('`')[1] set_classes(options) classes = [] if 'classes' in options: classes += options['classes'] del options['classes'] # If language is not specified, render a simple literal if not 'language' in options: content = nodes.raw('', utils.unescape(text), format='html') node = nodes.literal(rawtext, '', **options) node.append(content) return [node], [] language = options['language'] del options['language'] # Not sure why language is duplicated in classes? if language in classes: classes.remove(language) class_, highlighted = _highlight(utils.unescape(text), language, options, is_block=False) classes += [class_] content = nodes.raw('', highlighted, format='html') node = nodes.literal(rawtext, '', classes=classes, **options) node.append(content) return [node], []
def index_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): # create new reference target env = inliner.document.settings.env targetid = 'index-%s' % env.new_serialno('index') targetnode = nodes.target('', '', ids=[targetid]) # split text and target in role content has_explicit_title, title, target = split_explicit_title(text) title = utils.unescape(title) target = utils.unescape(target) # if an explicit target is given, we can process it as a full entry if has_explicit_title: entries = process_index_entry(target, targetid) # otherwise we just create a "single" entry else: # but allow giving main entry main = '' if target.startswith('!'): target = target[1:] title = title[1:] main = 'main' entries = [('single', target, targetid, main)] indexnode = addnodes.index() indexnode['entries'] = entries set_role_source_info(inliner, lineno, indexnode) textnode = nodes.Text(title, title) return [indexnode, targetnode, textnode], []
def indexmarkup_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): """Role for PEP/RFC references that generate an index entry.""" env = inliner.document.settings.env if not typ: typ = env.config.default_role else: typ = typ.lower() has_explicit_title, title, target = split_explicit_title(text) # type: bool, unicode, unicode # NOQA title = utils.unescape(title) target = utils.unescape(target) targetid = 'index-%s' % env.new_serialno('index') indexnode = addnodes.index() targetnode = nodes.target('', '', ids=[targetid]) inliner.document.note_explicit_target(targetnode) if typ == 'pep': indexnode['entries'] = [ ('single', _('Python Enhancement Proposals; PEP %s') % target, targetid, '', None)] anchor = '' # type: unicode anchorindex = target.find('#') if anchorindex > 0: target, anchor = target[:anchorindex], target[anchorindex:] if not has_explicit_title: title = "PEP " + utils.unescape(title) try: pepnum = int(target) except ValueError: msg = inliner.reporter.error('invalid PEP number %s' % target, line=lineno) prb = inliner.problematic(rawtext, rawtext, msg) return [prb], [msg] ref = inliner.document.settings.pep_base_url + 'pep-%04d' % pepnum sn = nodes.strong(title, title) rn = nodes.reference('', '', internal=False, refuri=ref+anchor, classes=[typ]) rn += sn return [indexnode, targetnode, rn], [] elif typ == 'rfc': indexnode['entries'] = [ ('single', 'RFC; RFC %s' % target, targetid, '', None)] anchor = '' anchorindex = target.find('#') if anchorindex > 0: target, anchor = target[:anchorindex], target[anchorindex:] if not has_explicit_title: title = "RFC " + utils.unescape(title) try: rfcnum = int(target) except ValueError: msg = inliner.reporter.error('invalid RFC number %s' % target, line=lineno) prb = inliner.problematic(rawtext, rawtext, msg) return [prb], [msg] ref = inliner.document.settings.rfc_base_url + inliner.rfc_url % rfcnum sn = nodes.strong(title, title) rn = nodes.reference('', '', internal=False, refuri=ref+anchor, classes=[typ]) rn += sn return [indexnode, targetnode, rn], []
def wikipedia_role(name, rawtext, text, lineno, inliner, options={}, content=[]): has_title, title, target = split_explicit_title(text) title = utils.unescape(title) target = utils.unescape(target) target = target.replace(' ', '_') refnode = nodes.reference(title, title, refuri=WIKIPEDIA_URI % target) return [refnode], []
def user_role(name, rawtext, text, lineno, inliner, options=None, content=None): """Sphinx role for linking to a user profile. Defaults to linking to Github profiles, but the profile URIS can be configured via the ``issues_user_uri`` config value. Examples: :: :user:`sloria` Anchor text also works: :: :user:`Steven Loria <sloria>` """ options = options or {} content = content or [] has_explicit_title, title, target = split_explicit_title(text) target = utils.unescape(target).strip() title = utils.unescape(title).strip() config = inliner.document.settings.env.app.config if config.issues_user_uri: ref = config.issues_user_uri.format(user=target) else: ref = "https://github.com/{0}".format(target) if has_explicit_title: text = title else: text = "@{0}".format(target) link = nodes.reference(text=text, refuri=ref, **options) return [link], []
def role(typ, rawtext, text, lineno, inliner, options={}, content=[]): if not extension.is_isolated: content = Element('span') content.text = utils.unescape(text) else: content = utils.unescape(text) element = extension.process({}, content) return [zeml(zeml=element)], []
def issue_reference(self, match, lineno): text = match.group(0) rawsource = unescape(text, True) text = unescape(text, False) refuri = 'https://issues.apache.org/jira/browse/' + text return [nodes.reference(rawsource, text, refuri=refuri)]
def process_link(self, env, refnode, has_explicit_title, title, target): """Called after parsing title and target text, and creating the reference node (given in *refnode*). This method can alter the reference node and must return a new (or the same) ``(title, target)`` tuple. """ #~ print(20130901, refnode, has_explicit_title, title, target) #~ 20130901 <pending_xref refdomain="" refexplicit="False" reftype="ddref"/> False cal.Event cal.Event target = ws_re.sub(' ', target) # replace newlines or tabs by spaces # ~ target = ' '.join(target.split()) # replace newlines or tabs by spaces level, x = resolve_name(target) if x is None: msg = "Could not resolve name %r" % target return [self._reporter.warning(msg, line=self._lineno), target] # raise Exception(msg) # lng = env.temp_data.get('language', env.config.language) lng = CurrentLanguage.get_current_value(env) with translation.override(lng): if isinstance(x, models.Field): text = utils.unescape(str(x.verbose_name)) target = model_name(x.model) + '.' + x.name # print(target) elif isinstance(x, Plugin): text = utils.unescape(str(x.verbose_name)) target = settings.SITE.userdocs_prefix + target elif isinstance(x, type) and issubclass(x, models.Model): text = utils.unescape(str(x._meta.verbose_name)) target = model_name(x) elif isinstance(x, type) and issubclass(x, actors.Actor): text = utils.unescape(str(x.title or x.label)) target = actor_name(x) elif isinstance(x, actions.Action): text = utils.unescape(str(x.label)) target = actor_name(x) else: raise Exception("Don't know how to handle %r" % x) if not has_explicit_title: # avoid replacing title by the heading text refnode['refexplicit'] = True title = text refnode['refwarn'] = False # never warn #~ refnode['reftype'] = 'ref' #~ title = "[%s]" % title #~ if target == 'welfare.reception.waitingvisitors': #~ print("20130907 ddref to %s : title=%r" % (target,title)) return title, target
def role_mochidef(role, rawtext, text, lineno, inliner, options=None, content=[]): if options is None: options = {} base, name = mochi_name(text) assert base == "" ref = "fn-" + utils.unescape(name.lower()) anchor = nodes.raw("", '\n<a name="%s"></a>\n' % (ref,), format="html") roles.set_classes(options) options.setdefault("classes", []).append("mochidef") node = nodes.reference(text, utils.unescape(text), refuri="#" + ref, **options) return [anchor, node], []
def role_mochidef(role, rawtext, text, lineno, inliner, options=None, content=[]): if options is None: options = {} base, name = mochi_name(text) assert base == '' ref = 'fn-' + utils.unescape(name.lower()) anchor = nodes.raw('', '\n<a name="%s"></a>\n' % (ref,), format='html') roles.set_classes(options) options.setdefault('classes', []).append('mochidef') node = nodes.reference( text, utils.unescape(text), refuri='#' + ref, **options) return [anchor, node], []
def standalone_uri(self, match, lineno): if (not match.group('scheme') or match.group('scheme').lower() in urischemes.schemes): if match.group('email'): addscheme = 'mailto:' else: addscheme = '' text = match.group('whole') unescaped = unescape(text, 0) return [nodes.reference(unescape(text, 1), unescaped, refuri=addscheme + unescaped)] else: # not a valid scheme raise MarkupMismatch
def __call__(self, name, rawtext, text, lineno, inliner, options={}, content=[]): # type: (str, str, str, int, Inliner, Dict, List[str]) -> Tuple[List[nodes.Node], List[nodes.system_message]] # NOQA matched = self.explicit_title_re.match(text) if matched: self.has_explicit_title = True self.title = unescape(matched.group(1)) self.target = unescape(matched.group(2)) else: self.has_explicit_title = False self.title = unescape(text) self.target = unescape(text) return super().__call__(name, rawtext, text, lineno, inliner, options, content)
def __call__(self, typ, rawtext, text, lineno, inliner, options={}, content=[]): # type: (unicode, unicode, unicode, int, Inliner, Dict, List[unicode]) -> Tuple[List[nodes.Node], List[nodes.Node]] # NOQA env = inliner.document.settings.env if not typ: typ = env.temp_data.get('default_role') if not typ: typ = env.config.default_role if not typ: raise SphinxError('cannot determine default role!') else: typ = typ.lower() if ':' not in typ: domain, role = '', typ # type: unicode, unicode classes = ['xref', role] else: domain, role = typ.split(':', 1) classes = ['xref', domain, '%s-%s' % (domain, role)] # if the first character is a bang, don't cross-reference at all if text[0:1] == '!': text = utils.unescape(text)[1:] if self.fix_parens: text, tgt = self._fix_parens(env, False, text, "") innernode = self.innernodeclass(rawtext, text, classes=classes) return self.result_nodes(inliner.document, env, innernode, is_ref=False) # split title and target in role content has_explicit_title, title, target = split_explicit_title(text) title = utils.unescape(title) target = utils.unescape(target) # fix-up title and target if self.lowercase: target = target.lower() if self.fix_parens: title, target = self._fix_parens( env, has_explicit_title, title, target) # create the reference node refnode = self.nodeclass(rawtext, reftype=role, refdomain=domain, refexplicit=has_explicit_title) # we may need the line number for warnings set_role_source_info(inliner, lineno, refnode) # type: ignore title, target = self.process_link( env, refnode, has_explicit_title, title, target) # now that the target and title are finally determined, set them refnode['reftarget'] = target refnode += self.innernodeclass(rawtext, title, classes=classes) # we also need the source document refnode['refdoc'] = env.docname refnode['refwarn'] = self.warn_dangling # result_nodes allow further modification of return values return self.result_nodes(inliner.document, env, refnode, is_ref=True)
def add_raw_to_list_items( # The directive object, for use in error reporting directive, # A list containing a single container node with contents as described above. content_nodes, # The raw text passed to the directive. block_text, # HTML to append to the end of the list, which will contain feedback. feedback_html, # Raw HTML to prepend to each list_item. pre_html, # Raw HTML to append to each list_item post_html='</label>'): try: # Make sure we got a Container and a ``bullet_list``. assert isinstance(content_nodes[0], nodes.container) bullet_list = content_nodes[0][0] assert isinstance(bullet_list, nodes.bullet_list) # Walk through each list item. for list_item in bullet_list: # Make sure the structure is as expected (see above). assert isinstance(list_item, nodes.list_item) para = list_item[0] assert isinstance(para, nodes.paragraph) # Insert a checkbox at the beginning of the paragraph. raw_prefix_node = nodes.raw(block_text, utils.unescape(pre_html, 1), format='html') # Hack: there's not an insert method, so copy from ``docutils.nodes.Element.append``. para.setup_child(raw_prefix_node) para.children.insert(0, raw_prefix_node) # Insert the ``</label>`` at the end of the paragraph. raw_suffix_node = nodes.raw(block_text, utils.unescape(post_html, 1), format='html') para += raw_suffix_node except AssertionError as e: raise directive.error('Unexpected document structure: {}.'.format(e)) # Add a final list item which will contain feedback. bullet_list = content_nodes[0][0] list_item = nodes.list_item(block_text) para = nodes.paragraph(block_text) raw_feedback = nodes.raw(block_text, utils.unescape(feedback_html, 1), format='html') bullet_list += list_item list_item += para para += raw_feedback
def cve_role(name, rawtext, text, lineno, inliner, options=None, content=None): """Sphinx role for linking to a CVE on https://cve.mitre.org. Examples: :: :cve:`CVE-2018-17175` """ options = options or {} content = content or [] has_explicit_title, title, target = split_explicit_title(text) target = utils.unescape(target).strip() title = utils.unescape(title).strip() ref = "https://cve.mitre.org/cgi-bin/cvename.cgi?name={0}".format(target) text = title if has_explicit_title else target link = nodes.reference(text=text, refuri=ref, **options) return [link], []
def code_role(role, rawtext, text, lineno, inliner, options={}, content=[]): set_classes(options) language = options.get('language', '') classes = ['code'] if 'classes' in options: classes.extend(options['classes']) if language and language not in classes: classes.append(language) try: tokens = Lexer(utils.unescape(text, 1), language, inliner.document.settings.syntax_highlight) except LexerError as error: msg = inliner.reporter.warning(error) prb = inliner.problematic(rawtext, rawtext, msg) return [prb], [msg] node = nodes.literal(rawtext, '', classes=classes) # analyze content and add nodes for every token for classes, value in tokens: # print (classes, value) if classes: node += nodes.inline(value, value, classes=classes) else: # insert as Text to decrease the verbosity of the output node += nodes.Text(value, value) return [node], []
def blogref_role(name, rawtext, text, lineno, inliner, options={}, content=[]): """ Inserts a reference to the blog entry of the specified date. Instead of writing ``:doc:`/blog/2011/0406``` it is better to write ``:blogref:`20110406``` because the latter works between Sphinx trees and also supports archived blog entries. """ # thanks to http://docutils.sourceforge.net/docs/howto/rst-roles.html # this code originally from roles.pep_reference_role #~ print 20130315, rawtext, text, utils.unescape(text) has_explicit_title, title, target = split_explicit_title(text) try: date = i2d(int(target)) except ValueError: msg = inliner.reporter.error( 'Invalid text %r: must be an integer date of style "20130315" .' % text, line=lineno) prb = inliner.problematic(rawtext, rawtext, msg) return [prb], [msg] #~ print repr(env) #~ raise Exception(20130315) #~ ref = inliner.document.settings.pep_base_url #~ + inliner.document.settings.pep_file_url_template % date) roles.set_classes(options) #~ from django.conf import settings #~ shown_text = settings.SITE.dtos(date) env = inliner.document.settings.env if not has_explicit_title: title = date.strftime(env.settings.get('today_fmt', '%Y-%m-%d')) title = utils.unescape(title) return [nodes.reference(rawtext, title, refuri=get_blog_url(date), **options)], []
def generic_custom_role(role, rawtext, text, lineno, inliner, options={}, content=[]): """""" # Once nested inline markup is implemented, this and other methods should # recursively call inliner.nested_parse(). set_classes(options) return [nodes.inline(rawtext, utils.unescape(text), **options)], []
def issues_role(name, rawtext, text, lineno, inliner, options={}, content=[]): """ Use: :issue|bug|feature|support:`ticket number` When invoked as :issue:, turns into just a "#NN" hyperlink to Github. When invoked otherwise, turns into "[Type] <#NN hyperlink>: ". """ # Old-style 'just the issue link' behavior issue_no = utils.unescape(text) ref = "https://github.com/fabric/fabric/issues/" + issue_no link = nodes.reference(rawtext, '#' + issue_no, refuri=ref, **options) ret = [link] # Additional 'new-style changelog' stuff if name in issue_types: which = '[<span class="changelog-%s">%s</span>]' % ( name, name.capitalize() ) ret = [ nodes.raw(text=which, format='html'), nodes.inline(text=" "), link, nodes.inline(text=":") ] return ret, []
def coderef_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): text = utils.unescape(text) has_explicit_title, title, target = split_explicit_title(text) try: modname, name = target.rsplit('.', 1) except ValueError: raise Exception("Don't know how to import name %s" % target) mod = import_module(modname) try: value = getattr(mod, name, None) except AttributeError: raise Exception("No name '%s' in module '%s'" % (name, modname)) #~ raise Exception("20130908 %s " % lines) if isinstance(value, type): if value.__module__ != modname: raise Exception("20130908 %r != %r" % (value.__module__, modname)) url = srcref(mod) lines, line_no = inspect.getsourcelines(value) if line_no: url += "#" + str(line_no) if not has_explicit_title: pass pnode = nodes.reference(title, title, internal=False, refuri=url) return [pnode], []
def menusel_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): # type: (unicode, unicode, unicode, int, Inliner, Dict, List[unicode]) -> Tuple[List[nodes.Node], List[nodes.Node]] # NOQA env = inliner.document.settings.env if not typ: assert env.temp_data['default_role'] typ = env.temp_data['default_role'].lower() else: typ = typ.lower() text = utils.unescape(text) if typ == 'menuselection': text = text.replace('-->', u'\N{TRIANGULAR BULLET}') spans = _amp_re.split(text) node = nodes.inline(rawtext=rawtext) for i, span in enumerate(spans): span = span.replace('&&', '&') if i == 0: if len(span) > 0: textnode = nodes.Text(span) node += textnode continue accel_node = nodes.inline() letter_node = nodes.Text(span[0]) accel_node += letter_node accel_node['classes'].append('accelerator') node += accel_node textnode = nodes.Text(span[1:]) node += textnode node['classes'].append(typ) return [node], []
def resolve_api_name(n, rawtext, text, lineno, inliner, options={}, content=[]): if docutils is None: raise AssertionError('requires docutils') # Check if there's separate text & targets m = _TARGET_RE.match(text) if m: text, target = m.groups() else: target = text # node in monotype font text = utils.unescape(text) node = nodes.literal(rawtext, text, **options) # Get the resolver from the register and create an url from it. try: url = api_register[name].get_url(target) except IndexError as exc: msg = inliner.reporter.warning(str(exc), line=lineno) if problematic: prb = inliner.problematic(rawtext, text, msg) return [prb], [msg] else: return [node], [] if url is not None: node = nodes.reference(rawtext, '', node, refuri=url, **options) return [node], []
def xapian_code_example_role(typ, rawtext, etext, lineno, inliner, options=(), content=[]): ex = utils.unescape(etext) if ex == '^' and last_example: ex = last_example code_path = xapian_code_example_filename(ex) return [github_link_node(code_path, code_path, options)], []
def xapian_method_role(typ, rawtext, etext, lineno, inliner, options=(), content=[]): cm = utils.unescape(etext) if highlight_language == 'c++': return [nodes.literal(text = 'Xapian::' + cm)], [] elif highlight_language == 'csharp': # FIXME: Need to adjust method names for csharp cm = re.sub(r'::', r'.', cm) return [nodes.literal(text = 'Xapian.' + cm)], [] elif highlight_language == 'java': # FIXME: Need to adjust method names for java cm = re.sub(r'::', r'.', cm) return [nodes.literal(text = 'org.xapian.' + cm)], [] elif highlight_language == 'lua': return [nodes.literal(text = 'xapian.' + cm)], [] elif highlight_language == 'perl': # Add a $ in front of each parameter. cm = decorate_variables(cm) return [nodes.literal(text = 'Search::Xapian::' + cm)], [] elif highlight_language == 'php': # Add a $ in front of each parameter. cm = decorate_variables(cm) return [nodes.literal(text = 'Xapian' + cm)], [] elif highlight_language.startswith('python'): cm = re.sub(r'::', r'.', cm) return [nodes.literal(text = 'xapian.' + cm)], [] elif highlight_language == 'ruby': # FIXME: Need to adjust method names for ruby return [nodes.literal(text = 'Xapian::' + cm)], [] elif highlight_language == 'tcl': return [nodes.literal(text = 'xapian::' + cm)], [] else: print "Unhandled highlight_language '%s'" % highlight_language sys.exit(1)
def generate_uri_role( role_name, aliases, anchor_text, base_url, interpret_url, validator): '''Creates and register a uri based "interpreted role". Those are similar to the RFC, and PEP ones, and take role_name: name that will be registered aliases: list of alternate names anchor_text: text that will be used, together with the role base_url: base url for the link interpret_url: this, modulo the validated text, will be added to it validator: should return the validated text, or raise ValueError ''' def uri_reference_role(role, rawtext, text, lineno, inliner, options={}, content=[]): try: valid_text = validator(text) except ValueError, e: msg = inliner.reporter.error( e.message % dict(text=text), line=lineno) prb = inliner.problematic(rawtext, rawtext, msg) return [prb], [msg] ref = base_url + interpret_url % valid_text set_classes(options) node = nodes.reference(rawtext, anchor_text + utils.unescape(text), refuri=ref, **options) return [node], []
def make_link_node(rawtext, app, type, slug, options): """Create a link to a github resource. :param rawtext: Text being replaced with link node. :param app: Sphinx application context :param type: Link type (issues, changeset, etc.) :param slug: ID of the thing to link to :param options: Options dictionary passed to role func. """ try: base = app.config.github_project_url if not base: raise AttributeError if not base.endswith('/'): base += '/' except AttributeError as err: raise ValueError('github_project_url configuration value is not set (%s)' % str(err)) ref = base + type + '/' + slug + '/' set_classes(options) prefix = "#" if type == 'pull': prefix = "PR " + prefix node = nodes.reference(rawtext, prefix + utils.unescape(slug), refuri=ref, **options) return node
def trac_changeset_role(name, rawtext, text, lineno, inliner, options={}, content=[]): app = inliner.document.settings.env.app try: base = app.config.trac_url if not base: raise AttributeError except AttributeError: #, err: msg = 'trac_url configuration value is not set (%s)' raise ValueError(msg % str(err)) slash = '/' if base[-1] != '/' else '' unescaped = utils.unescape(text) prefix = 'changeset ' node = nodes.literal(prefix, prefix) # Hard-coded for NetworkX if unescaped.endswith('networkx-svn-archive'): # Use the integer display = unescaped.split('/')[0] else: # hg: use the first 12 hash characters display = unescaped[:12] uri = base + slash + 'changeset/' + text node += nodes.reference(rawtext, display, refuri=uri, **options) return [node], []
def xapian_class_role(typ, rawtext, etext, lineno, inliner, options=(), content=[]): c = utils.unescape(etext) if highlight_language == 'c++': return [nodes.literal(text = 'Xapian::' + c)], [] elif highlight_language == 'csharp': return [nodes.literal(text = 'Xapian.' + c)], [] elif highlight_language == 'java': return [nodes.literal(text = 'org.xapian.' + c)], [] elif highlight_language == 'lua': return [nodes.literal(text = 'xapian.' + c)], [] elif highlight_language == 'perl': return [nodes.literal(text = 'Search::Xapian::' + c)], [] elif highlight_language == 'php': return [nodes.literal(text = 'Xapian' + c)], [] elif highlight_language == 'python': return [nodes.literal(text = 'xapian.' + c)], [] elif highlight_language == 'python3': return [nodes.literal(text = 'xapian.' + c)], [] elif highlight_language == 'ruby': return [nodes.literal(text = 'Xapian::' + c)], [] elif highlight_language == 'tcl': return [nodes.literal(text = 'xapian::' + c)], [] else: print "Unhandled highlight_language '%s'" % highlight_language sys.exit(1)
def glyph_role(name, rawtext, text, lineno, inliner, options={}, content=[]): """ This function defines a glyph inline role that show a glyph icon from the twitter bootstrap framework *Usage:* :glyph:`<glyph_name>` *Example:* Love this music :glyph:`music` :) Can be subclassed to include a target *Example:* .. role:: story_time_glyph(glyph) :target: http://www.youtube.com/watch?v=5g8ykQLYnX0 :class: small text-info Love this music :story_time_glyph:`music` :) """ target = options.get('target', None) glyph_name = 'glyphicon-{}'.format(text) if target: target = utils.unescape(target) new_element = nodes.reference(rawtext, ' ', refuri=target) else: new_element = nodes.container() classes = options.setdefault('class', []) classes += ['glyphicon', glyph_name] for custom_class in classes: new_element.set_class(custom_class) return [new_element], []
def ticket_role(name, rawtext, text, lineno, inliner, options={}, content=[]): cfg = inliner.document.settings.env.app.config if cfg.ticket_url is None: msg = inliner.reporter.warning( "ticket not configured: please configure ticket_url in conf.py") prb = inliner.problematic(rawtext, rawtext, msg) return [prb], [msg] rv = [nodes.Text(name + ' ')] tokens = re.findall(r'(#?\d+)|([^\d#]+)', text) for ticket, noise in tokens: if ticket: num = int(ticket.replace('#', '')) # Push numbers of the oldel tickets ahead. # We moved the tickets from a different tracker to GitHub and the # latter already had a few ticket numbers taken (as merge # requests). remap_until = cfg.ticket_remap_until remap_offset = cfg.ticket_remap_offset if remap_until and remap_offset: if num <= remap_until: num += remap_offset url = cfg.ticket_url % num roles.set_classes(options) node = nodes.reference(ticket, utils.unescape(ticket), refuri=url, **options) rv.append(node) else: assert noise rv.append(nodes.Text(noise)) return rv, []
def issues_role(name, rawtext, text, lineno, inliner, options={}, content=[]): """ Use: :issue|bug|feature|support:`ticket number` When invoked as :issue:, turns into just a "#NN" hyperlink to Github. When invoked otherwise, turns into "[Type] <#NN hyperlink>: ". """ # Old-style 'just the issue link' behavior issue_no = utils.unescape(text) ref = "https://github.com/aol/trigger/issues/" + issue_no link = nodes.reference(rawtext, '#' + issue_no, refuri=ref, **options) ret = [link] # Additional 'new-style changelog' stuff if name in issue_types: which = '[<span class="changelog-%s">%s</span>]' % (name, name.capitalize()) ret = [ nodes.raw(text=which, format='html'), nodes.inline(text=" "), link, nodes.inline(text=":") ] return ret, []
def trac_ticket_role(name, rawtext, text, lineno, inliner, options={}, content=[]): app = inliner.document.settings.env.app try: base = app.config.trac_url if not base: raise AttributeError except AttributeError as err: msg = 'trac_url configuration value is not set (%s)' raise ValueError(msg % str(err)) slash = '/' if base[-1] != '/' else '' prefix = 'ticket ' node = nodes.literal(prefix, prefix) display = utils.unescape(text) uri = base + slash + 'ticket/' + text node += nodes.reference(rawtext, display, refuri=uri, **options) return [node], []
def php_phpclass_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): text = utils.unescape(text) has_explicit_title, title, full_class = split_explicit_title(text) full_url = 'http://php.net/manual/en/class.%s.php' % lower(full_class) if not has_explicit_title: title = full_class list = [ nodes.reference(title, title, internal=False, refuri=full_url, reftitle=full_class) ] pnode = nodes.literal('', '', *list) return [pnode], []
def make_wikipedia_link(name, rawtext, text, lineno, inliner, options={}, content=[]): env = inliner.document.settings.env lang = env.config.wikipedia_lang text = utils.unescape(text) has_explicit, title, target = split_explicit_title(text) m = re.match(r'\:(.*?)\:(.*)', target) if m: lang, target = m.groups() if not has_explicit: title = target ref = base_url % lang + urllib.quote( target.replace(' ', '_').encode('utf8'), safe='') node = nodes.reference(rawtext, title, refuri=ref, **options) return [node], []
def uri_reference_role(role, rawtext, text, lineno, inliner, options=None, content=None): if options is None: options = {} try: valid_text = validator(text) except ValueError as e: msg = inliner.reporter.error(e.message % dict(text=text), line=lineno) prb = inliner.problematic(rawtext, rawtext, msg) return [prb], [msg] ref = base_url + interpret_url % valid_text set_classes(options) node = nodes.reference(rawtext, anchor_text + utils.unescape(text), refuri=ref, **options) return [node], []
def nicovideo_role(name, rawtext, text, lineno, inliner, options={}, content=[]): """Role for linking to nicovideo pages.""" text = utils.unescape(text) has_explicit, title, movie_id = split_explicit_title(text) try: movie = NicoVideo(movie_id) if has_explicit == False: title = movie.title ref = nodes.reference(rawtext, title, refuri=movie.url) return [ref], [] except: msg = inliner.reporter.error('fail to load nicovideo: %s' % movie_id, line=lineno) prb = inliner.problematic(rawtext, rawtext, msg) return [prb], [msg]
def run(self): if not isinstance(self.state, states.SubstitutionDef): raise self.error( 'Invalid context: the "%s" directive can only be used within ' 'a substitution definition.' % self.name) substitution_definition = self.state_machine.node if 'trim' in self.options: substitution_definition.attributes['ltrim'] = 1 substitution_definition.attributes['rtrim'] = 1 if 'ltrim' in self.options: substitution_definition.attributes['ltrim'] = 1 if 'rtrim' in self.options: substitution_definition.attributes['rtrim'] = 1 codes = self.comment_pattern.split(self.arguments[0])[0].split() element = nodes.Element() for code in codes: try: decoded = directives.unicode_code(code) except ValueError as error: raise self.error('Invalid character code: %s\n%s' % (code, ErrorString(error))) element += nodes.Text(utils.unescape(decoded), decoded) return element.children
def pep_reference_role(role, rawtext, text, lineno, inliner, options={}, content=[]): try: pepnum = int(utils.unescape(text)) if pepnum < 0 or pepnum > 9999: raise ValueError except ValueError: msg = inliner.reporter.error( 'PEP number must be a number from 0 to 9999; "%s" is invalid.' % text, line=lineno) prb = inliner.problematic(rawtext, rawtext, msg) return [prb], [msg] # Base URL mainly used by inliner.pep_reference; so this is correct: ref = (inliner.document.settings.pep_base_url + inliner.document.settings.pep_file_url_template % pepnum) set_classes(options) return [nodes.reference(rawtext, 'PEP ' + text, refuri=ref, **options)], []
def role(typ, rawtext, text, lineno, inliner, options={}, content=[]): text = utils.unescape(text) has_explicit_title, title, part = split_explicit_title(text) pnodes = [] for base_url, prefix in zip(base_urls, prefixes): full_url = base_url.format(part) if not has_explicit_title: if prefix is None: title = full_url else: title = prefix.format(part) ref = nodes.reference(title, title, internal=False, refuri=full_url) if len(pnodes) == 1: pnodes.append(nodes.Text(" [")) if len(pnodes) > 2: pnodes.append(nodes.Text(", ")) pnodes.append(ref) if len(base_urls) > 1: pnodes.append(nodes.Text("]")) return pnodes, []
def _role_annot( name: str, rawtext: str, text: str, lineno: int, inliner: Inliner, options: Dict[str, Any] = {}, content: Sequence[str] = (), # *, # https://github.com/ambv/black/issues/613 additional_classes: Iterable[str] = (), ) -> Tuple[List[Node], List[SystemMessage]]: options = options.copy() set_classes(options) if additional_classes: options["classes"] = options.get("classes", []).copy() options["classes"].extend(additional_classes) memo = Struct(document=inliner.document, reporter=inliner.reporter, language=inliner.language) node = nodes.inline(unescape(rawtext), "", **options) children, messages = inliner.parse(_unescape(text), lineno, memo, node) node.extend(children) return [node], messages
def make_link_node(rawtext, app, type, slug, options): """Create a link to a Redmine resource. :param rawtext: Text being replaced with link node. :param app: Sphinx application context :param type: Link type (issue, changeset, etc.) :param slug: ID of the thing to link to :param options: Options dictionary passed to role func. """ # try: base = app.config.redmine_project_url if not base: raise AttributeError except AttributeError: raise ValueError('redmine_project_url configuration value is not set') # slash = '/' if base[-1] != '/' else '' ref = base + slash + type + '/' + slug + '/' set_classes(options) node = nodes.reference(rawtext, 'Issue #' + utils.unescape(slug), refuri=ref, **options) return node
def php_method_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): text = utils.unescape(text) env = inliner.document.settings.env base_url = env.app.config.api_url has_explicit_title, title, class_and_method = split_explicit_title(text) ns = class_and_method.rfind('::') full_class = class_and_method[:ns] method = class_and_method[ns + 2:] full_class = "classes/" + full_class try: full_url = base_url % full_class.replace( '\\', '.') + '.html' + '#method_' + method except (TypeError, ValueError): env.warn( env.docname, 'unable to expand %s api_url with base ' 'URL %r, please make sure the base contains \'%%s\' ' 'exactly once' % (typ, base_url)) full_url = base_url + utils.escape(full_class) if not has_explicit_title: title = method + '()' list = [ nodes.reference(title, title, internal=False, refuri=full_url, reftitle=full_class + '::' + method + '()') ] pnode = nodes.literal('', '', *list) return [pnode], []
def menusel_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): # type: (str, str, str, int, Inliner, Dict, List[str]) -> Tuple[List[nodes.Node], List[nodes.system_message]] # NOQA warnings.warn( 'menusel_role() is deprecated. ' 'Please use MenuSelection or GUILabel class instead.', RemovedInSphinx40Warning, stacklevel=2) env = inliner.document.settings.env if not typ: assert env.temp_data['default_role'] typ = env.temp_data['default_role'].lower() else: typ = typ.lower() text = utils.unescape(text) if typ == 'menuselection': text = text.replace('-->', '\N{TRIANGULAR BULLET}') spans = _amp_re.split(text) node = nodes.inline(rawtext=rawtext) for i, span in enumerate(spans): span = span.replace('&&', '&') if i == 0: if len(span) > 0: textnode = nodes.Text(span) node += textnode continue accel_node = nodes.inline() letter_node = nodes.Text(span[0]) accel_node += letter_node accel_node['classes'].append('accelerator') node += accel_node textnode = nodes.Text(span[1:]) node += textnode node['classes'].append(typ) return [node], []
def jira_role(name, rawtext, text, lineno, inliner, options=None, content=None, oxford_comma=True): """Sphinx role for referencing a JIRA ticket. Examples:: :jira:`DM-6181` -> DM-6181 :jira:`DM-6181,DM-6181` -> DM-6180 and DM-6181 :jira:`DM-6181,DM-6181,DM-6182` -> DM-6180, DM-6181, and DM-6182 """ options = options or {} content = content or [] config = inliner.document.settings.env.app.config ticket_ids = [each.strip() for each in utils.unescape(text).split(',')] n_tickets = len(ticket_ids) if oxford_comma: sep_factory = _oxford_comma_separator else: sep_factory = _comma_separator node_list = [] for i, ticket_id in enumerate(ticket_ids): node = _make_ticket_node(ticket_id, config, options=options) node_list.append(node) sep_text = sep_factory(i, n_tickets) if sep_text is not None: sep = nodes.raw(text=sep_text, format='html') node_list.append(sep) return node_list, []
def make_link_node(rawtext, app, name, options): """ Create a link to the TL reference. :param rawtext: Text being replaced with link node. :param app: Sphinx application context :param name: Name of the object to link to :param options: Options dictionary passed to role func. """ try: base = app.config.tl_ref_url if not base: raise AttributeError except AttributeError as e: raise ValueError('tl_ref_url config value is not set') from e if base[-1] != '/': base += '/' set_classes(options) node = nodes.reference(rawtext, utils.unescape(name), refuri='{}?q={}'.format(base, name), **options) return node
def php_namespace_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): text = utils.unescape(text) env = inliner.document.settings.env base_url = env.app.config.api_url has_explicit_title, title, namespace = split_explicit_title(text) namespace = "namespaces/" + namespace try: full_url = base_url % namespace.replace('\\', '.') + '.html' except (TypeError, ValueError): env.warn( env.docname, 'unable to expand %s api_url with base ' 'URL %r, please make sure the base contains \'%%s\' ' 'exactly once' % (typ, base_url)) full_url = base_url + utils.escape(full_class) if not has_explicit_title: name = namespace.lstrip('\\') ns = name.rfind('\\') if ns != -1: name = name[ns + 1:] title = name list = [ nodes.reference(title, title, internal=False, refuri=full_url, reftitle=namespace) ] pnode = nodes.literal('', '', *list) return [pnode], []
def php_phpfunction_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): text = utils.unescape(text) has_explicit_title, title, full_function = split_explicit_title(text) full_url = 'http://php.net/manual/en/function.%s.php' % full_function.replace( '_', '-').lower() if not has_explicit_title: title = full_function list = [ nodes.reference(title, title, internal=False, refuri=full_url, reftitle=full_function) ] pnode = nodes.literal('', '', *list) return [pnode], []
def resolve_api_name(n, rawtext, text, lineno, inliner, options={}, content=[]): if docutils is None: raise AssertionError('requires docutils') # node in monotype font text = utils.unescape(text) node = nodes.literal(rawtext, text, **options) # Get the resolver from the register and create an url from it. try: url = api_register[name].get_url(text) except IndexError, exc: msg = inliner.reporter.warning(str(exc), line=lineno) if problematic: prb = inliner.problematic(rawtext, text, msg) return [prb], [msg] else: return [node], []
def role_trac(name, rawtext, text, lineno, inliner, options={}, content=[]): """ Aliases :trac:`1234` to 'https://trac.torproject.org/1234'. :param name: the role name used in the document :param rawtext: the entire markup snippet, with role :param text: the text marked with the role :param lineno: the line number where rawtext appears in the input :param inliner: the inliner instance that called us :param options: directive options for customization :param content: the directive content for customization """ # checking if the number is valid try: ticket_num = int(text) if ticket_num <= 0: raise ValueError except ValueError: msg = inliner.reporter.error('Invalid trac ticket: %s' % text, line=lineno) prb = inliner.problematic(rawtext, rawtext, msg) return ([prb], [msg]) app = inliner.document.settings.env.app link_text = 'ticket %s' % unescape(str(ticket_num)) return ( [ make_link_node(rawtext, app, 'trac_url', link_text, str(ticket_num), options) ], [], )
def menusel_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): text = utils.unescape(text) if typ == "menuselection": text = text.replace("-->", "\N{TRIANGULAR BULLET}") spans = _amp_re.split(text) node = nodes.emphasis(rawtext=rawtext) for i, span in enumerate(spans): span = span.replace("&&", "&") if i == 0: if len(span) > 0: textnode = nodes.Text(span) node += textnode continue accel_node = nodes.inline() letter_node = nodes.Text(span[0]) accel_node += letter_node accel_node["classes"].append("accelerator") node += accel_node textnode = nodes.Text(span[1:]) node += textnode node["classes"].append(typ) return [node], []
def rfc_reference_role(role, rawtext, text, lineno, inliner, options={}, content=[]): try: if "#" in text: rfcnum, section = text.split("#", 1) else: rfcnum, section = text, None rfcnum = int(rfcnum) if rfcnum <= 0: raise ValueError except ValueError: msg = inliner.reporter.error( 'RFC number must be a number greater than or equal to 1; ' '"%s" is invalid.' % text, line=lineno) prb = inliner.problematic(rawtext, rawtext, msg) return [prb], [msg] # Base URL mainly used by inliner.rfc_reference, so this is correct: ref = inliner.document.settings.rfc_base_url + inliner.rfc_url % rfcnum if section is not None: ref += "#"+section set_classes(options) node = nodes.reference(rawtext, 'RFC ' + utils.unescape(str(rfcnum)), refuri=ref, **options) return [node], []
def make_trac_link(name, rawtext, text, lineno, inliner, options={}, content=[]): # quick, dirty, and ugly... if '<' in text and '>' in text: full_name, label = text.split('<') full_name = full_name.strip() label = label.strip('>').strip() else: full_name = text label = full_name env = inliner.document.settings.env base_url = env.config.traclinks_base_url label = utils.unescape('ticket #' + label) ref = base_url + urllib.parse.quote(full_name, safe='') node = nodes.reference(rawtext, label, refuri=ref, **options) return [node], []
def make_api_link(name, rawtext, text, lineno, inliner, options={}, content=[]): from docutils import nodes, utils # quick, dirty, and ugly... if '<' in text and '>' in text: full_name, label = text.split('<') full_name = full_name.strip() label = label.strip('>').strip() else: full_name = label = text #get the base url for api links from the config file env = inliner.document.settings.env base_url = env.config.apilinks_base_url # not really sufficient, but just testing... # ...hmmm, maybe this is good enough after all ref = ''.join((base_url, full_name, '.html')) options.update(classes=["api"]) node = nodes.reference(rawtext, utils.unescape(label), refuri=ref, **options) nodes = [node] sys_msgs = [] return nodes, sys_msgs
def make_arts_link(name, rawtext, text, lineno, inliner, options={}, content=[]): parts = name.split(':') if len(parts) < 2 or parts[1] not in arts_elements: msg = inliner.reporter.error('Unknown arts role "{}".'.format(name), line=lineno) prb = inliner.problematic(rawtext, rawtext, msg) return [prb], [msg] kind = parts[1] env = inliner.document.settings.env docserver_url = env.config.arts_docserver_url.strip('/') uri = '/'.join([docserver_url, kind + 's', text]) node = nodes.reference(rawtext, utils.unescape(text), refuri=uri, **options) return [node], []
def role_github_pull_request_or_issue(name, rawtext, text, lineno, inliner, options=None, content=None): options = options or {} content = content or [] try: if int(text) <= 0: raise ValueError except ValueError: return sphinx_err( inliner, lineno, rawtext, 'GitHub pull request or issue number must be a number greater than or equal to 1; "%s" is invalid.' % text, ) if name == "pr": ref = gh_pr_uri elif name == "issue": ref = gh_issue_uri else: return sphinx_err( inliner, lineno, rawtext, 'unknown role name for GitHub reference - "%s"' % name, ) ref = ref.format(text) text = "#" + utils.unescape(text) return sphinx_ref(options, rawtext, text, ref)
def menusel_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): text = utils.unescape(text) if typ == 'menuselection': text = text.replace('-->', u'\N{TRIANGULAR BULLET}') spans = _amp_re.split(text) node = nodes.inline(rawtext=rawtext) for i, span in enumerate(spans): span = span.replace('&&', '&') if i == 0: if len(span) > 0: textnode = nodes.Text(span) node += textnode continue accel_node = nodes.inline() letter_node = nodes.Text(span[0]) accel_node += letter_node accel_node['classes'].append('accelerator') node += accel_node textnode = nodes.Text(span[1:]) node += textnode node['classes'].append(typ) return [node], []
def math_role(role, rawtext, text, lineno, inliner, options={}, content=[]): latex = utils.unescape(text, restore_backslashes=True) return [math(latex=latex)], []
def math_role(role, rawtext, text, lineno, inliner, options={}, content=[]): # type: (unicode, unicode, unicode, int, Inliner, Dict, List[unicode]) -> Tuple[List[nodes.Node], List[nodes.Node]] # NOQA latex = utils.unescape(text, restore_backslashes=True) return [math(latex=latex)], []