def _process_node(self, node): # Avoid literals etc if not isinstance(node.parent, nodes.paragraph): return in_str = node.rawsource processed = txt_dollars_to_math(in_str) if MATH_MARKER not in processed: return parts = processed.split(MATH_MARKER) new_nodes = [] for i, part in enumerate(parts): with_nulls = escape2null(part) to_backslashes = unescape(with_nulls, restore_backslashes=True) if part == '': continue if i % 2: # See sphinx.ext.mathbase if SPHINX_ge_18: new_node = math() new_node += nodes.Text(to_backslashes, to_backslashes) else: new_node = math(latex=to_backslashes) else: new_node = nodes.Text(unescape(with_nulls), to_backslashes) new_node.parent = node.parent new_nodes.append(new_node) # Put new nodes into parent's list of children new_children = [] for child in node.parent.children: if not child is node: new_children.append(child) else: new_children += new_nodes node.parent.children = new_children
def visit_Text(self, node): parent = node.parent while parent: if isinstance(parent, node_blacklist): if DEBUG and any(i == 'math' for i, _ in split_dollars(node.rawsource)): print("sphinx-math-dollar: Skipping", node, "(node_blacklist = %s)" % (node_blacklist, ), file=sys.stderr) return parent = parent.parent data = split_dollars(node.rawsource) nodes = [] has_math = False for typ, text in data: if typ == "math": has_math = True nodes.append(math(text, Text(text))) elif typ == "text": nodes.append(Text(text)) else: raise ValueError("Unrecognized type from split_dollars %r" % typ) if has_math: node.parent.replace(node, nodes)
def visit_Text(self, node): parent = node.parent while parent: if isinstance(parent, node_blacklist): if DEBUG and any(i == 'math' for i, _ in split_dollars(str(node).replace('\x00', '\\'))): print("sphinx-math-dollar: Skipping", node, "(node_blacklist = %s)" % (node_blacklist,), file=sys.stderr) return parent = parent.parent # See https://github.com/sympy/sphinx-math-dollar/issues/22 data = split_dollars(str(node).replace('\x00', '\\')) nodes = [] has_math = False for typ, text in data: if typ == "math": has_math = True nodes.append(math(text, Text(text))) elif typ == "text": nodes.append(Text(text)) elif typ == "display math": has_math = True new_node = math_block(text, Text(text)) new_node.attributes.setdefault('nowrap', False) new_node.attributes.setdefault('number', None) nodes.append(new_node) else: raise ValueError("Unrecognized type from split_dollars %r" % typ) if has_math: node.parent.replace(node, nodes)
def f_role( typ, rawtext, text, lineno, inliner, # pylint: disable=unused-argument options=None, content=None): # pylint: disable=unused-argument """ Role for formants caps. """ text = 'F_{}'.format(text) return [nodes.math(text, text)], []
def render_math_inline(self, token: SyntaxTreeNode) -> None: content = token.content if token.markup == "$$": # available when dmath_double_inline is True node = nodes.math_block(content, content, nowrap=False, number=None) else: node = nodes.math(content, content) self.add_line_and_source_path(node, token) self.current_node.append(node)
def render_math(self, token): if token.content.startswith("$$"): content = token.content[2:-2] node = nodes.math_block(content, content, nowrap=False, number=None) else: content = token.content[1:-1] node = nodes.math(content, content) self.add_line_and_source_path(node, token) self.current_node.append(node)
def render_text_latex(self, output: NotebookNode, index: int): data = output["data"]["text/latex"] return [ nodes.math( text=strip_latex_delimiters(data), nowrap=False, number=None, classes=["output", "text_latex"], ) ]
def render_text_latex_inline(self, data: MimeData) -> list[nodes.Element]: """Render a notebook text/latex mime data output.""" # TODO should we always assume this is math? return [ nodes.math( text=strip_latex_delimiters(data.string), nowrap=False, number=None, classes=["output", "text_latex"], ) ]
def render_text_latex(self, output: NotebookNode, index: int): data = output["data"]["text/latex"] self.env.get_domain("math").data["has_equations"][self.env.docname] = True return [ nodes.math( text=strip_latex_delimiters(data), nowrap=False, number=None, classes=["output", "text_latex"], ) ]
def ipa_role( typ, rawtext, text, lineno, inliner, # pylint: disable=unused-argument options=None, content=None): # pylint: disable=unused-argument """ Role for small caps. """ if text.startswith('/') and text.endswith('/'): text = '/\u200A{}\u2006/'.format(text[1:-1]) if r'^\prime' in rawtext: rawtext = rawtext[6:-1] parts = rawtext.split(r'^\prime') node = None for i, part in enumerate(parts): if part: if node: node += nodes.inline(part, part, classes=['ipa']) else: node = nodes.inline(part, part, classes=['ipa']) if i < len(parts) - 1: node += nodes.math(r'^\prime', r'^\prime') return [node], [] text = r'\mathstrut\mbox{' + text + r'}' return [nodes.math(text, text, )], []
def visit_script(self, node): if node.attrib.get("type", "").split(";")[0] == "math/tex": node.attrib.pop("type") parent = self.parse_stack_r[-1] if parent.tag == "span": return nodes.math() elif parent.tag == "div": # sphinx mathjax crashes without these attributes present math = nodes.math_block() math["nowrap"] = None math["number"] = None return math else: self.document.reporter.warning( "math/tex script with unknown parent: %s" % parent.tag) else: return IGNORE_ALL_CHILDREN
def make_node(self, cls, element): node = cls() having_block_node = cls in HAVING_BLOCK_NODE if element.text and element.text != "\n": text = self.unescape_char(element.text) if HTML_PLACEHOLDER_RE.search(text): html_text = self.unescape_char(text, rawHtml=True) if html_text.startswith("<!--math"): g = re.match(r"<!--math(.*?)-->", html_text, re.DOTALL) if g: node += nodes.math(text=g.group(1).strip(), latex=g.group(1).strip()) else: node += nodes.raw(format='html', text=html_text) elif having_block_node: node += nodes.paragraph(text=text) else: node += nodes.Text(text) for child in element: subnode = self.visit(child) if having_block_node and isinstance(subnode, INLINE_NODES): all_nodes_is_in_paragraph = True if len(node) == 0: node += nodes.paragraph() node[0] += subnode else: all_nodes_is_in_paragraph = False node += subnode if child.tail and child.tail != "\n": tail = self.unescape_char(child.tail) if HTML_PLACEHOLDER_RE.search(tail): node += nodes.raw(format='html', text=tail) elif all_nodes_is_in_paragraph: node[0] += nodes.Text(tail) elif having_block_node: node += nodes.paragraph(text=tail) else: node += nodes.Text(tail) return node
def visit_Text(self, node): parent = node.parent while parent: if isinstance(parent, node_blacklist): return parent = parent.parent rawtext = node.rawsource data = rawtext.split("@@") if len(data) == 1: return nodes = [] for i in range(len(data)): text = data[i] if i % 2 == 0: nodes.append(Text(text)) else: formula = eval(text, pygrim.__dict__) latex = formula.latex() #nodes.append(literal(text, text)) nodes.append(math(latex, Text(latex))) #nodes.append(math_block(latex, Text(latex))) node.parent.replace(node, nodes)
def render_math_single(self, token): content = token.content node = nodes.math(content, content) self.add_line_and_source_path(node, token) self.current_node.append(node)
def math_role(role, rawtext, text, lineno, inliner, options={}, content=[]): set_classes(options) text = utils.unescape(text, True) # raw text without inline role markup node = nodes.math(rawtext, text, **options) return [node], []
def math_role(role, rawtext, text, lineno, inliner, options={}, content=[]): set_classes(options) i = rawtext.find("`") text = rawtext.split("`")[1] node = nodes.math(rawtext, text, **options) return [node], []
def my_math_role(role, rawtext, text, lineno, inliner, options={}, content=[]): text = 'E = mc^2' return [nodes.math(text, text)], []
def ext_math_role(role, raw, text, line, inliner, options = {}, content = []): text = replace_mathdefs(inliner.document, raw.split('`')[1]) return [math(raw, text)], []
def math_role(role, rawtext, text, lineno, inliner, options={}, content=[]): i = rawtext.find('`') text = rawtext.split('`')[1] node = nodes.math(rawtext, text) return [node], []
def run(self): self.assert_has_content() env = self.state.document.settings.env if not hasattr(env, 'poi_all'): env.poi_all = {} if len(self.arguments) == 0: return [nodes.container()] if 'title' in self.options: if 'id' in self.options: raise SphinxError(u'Point of interest options can\'t contain both "title" and "id"; one of them should be provided as an argument instead') name = self.arguments[0] title_text = self.options['title'] else: name = self.options.get('id') if not name: choices = string.ascii_lowercase + string.digits while True: name = ''.join(random.choice(choices) for i in range(6)) if name not in env.poi_all: break title_text = self.arguments[0] node = nodes.container() title = nodes.container() if 'not_in_book' in self.options: # Ignore this point of interest in the output since it shall not be # included in the A+ course materials (e-book). return [] if 'no_poi_box' not in self.options: container_class = 'poi-container' content_name = name + '-content' # add an extra div to force content to desired height hcontainer_opts = { u'style': 'height:' + self.options.get('height', '') + ';', u'class': container_class + ' poi-content row', } else: container_class = 'no-poi-box' content_name = name hcontainer_opts = { u'style': 'height:' + self.options.get('height', '') + ';', u'class': 'row', } if 'bgimg' in self.options: static_host = os.environ.get('STATIC_CONTENT_HOST', None) if not static_host: logger.warning('Environment variable STATIC_CONTENT_HOST must be set to be able to use point of interest background', location=node) else: docname = env.docname imgname = self.options['bgimg'].split('/')[-1] imgpath = ('/').join(docname.split('/')[0:-1]) + '/' + self.options['bgimg'] urlstring = 'background-image:url(' + static_host + '/_images/' + imgname + ');' hcontainer_opts['style'] = hcontainer_opts['style'] + urlstring # Add background image to env and builder so that it will # be correctly copied to static _images build directory env.images[imgpath] = ({docname}, imgname) env.app.builder.images[imgpath] = imgname hcontainer = aplus_nodes.html(u'div', hcontainer_opts) collapsible = nodes.container() contentnodes = [] colseparator = '::newcol' colcontent = '' colcontent_l = [] colwidths = None prevl = 0 l = 0 if 'columns' in self.options: cols = list(map(int,self.options['columns'].split())) allcols = sum(cols) colwidths = [x / allcols for x in cols] for batch in self.content: l += 1 if batch == colseparator: cn = len(contentnodes) cwidth = None if colwidths: cwidth = floor(colwidths[cn] * 12) cnode = nodes.container(colcontent) hcontainer.append(cnode) contentnodes.append((self.content[prevl:l-1], self.content_offset + prevl, cnode, cwidth)) colcontent = '' prevl = l else: colcontent_l.append(batch) colcontent += batch colcontent += '\n' # add last column cnode = nodes.container(colcontent) hcontainer.append(cnode) cwidth = None if colwidths: cwidth = floor(colwidths[-1] * 12) contentnodes.append((self.content[prevl:], self.content_offset + prevl, cnode, cwidth)) nav = nodes.container() links = nodes.container() # poi_nav node is later replaced by reference nodes which # need to be within a TextElement-node text = nodes.inline() poinav = poi_nav() # Create a relative path to the _build/html/_static/poi.png file # from the built HTML file of the current RST document. dir_depth = len(os.path.dirname(env.doc2path(env.docname, None)).split(os.path.sep)) icon = aplus_nodes.html('img', { 'src': ('../' * dir_depth) + '_static/poi.png', 'alt': 'Point of interest icon', 'class': 'poi-icon', }) hidelink = aplus_nodes.html(u'a', { u'href':u'#' + content_name, u'data-toggle':u'collapse'}) hidelink.append(icon) if ":math:" in title_text: math_eq = title_text.split('`')[1] math_node = nodes.math() math_node['latex'] = math_eq hidelink.append(math_node) title.append(hidelink) nav.append(title) else: hidelink.append(nodes.Text(title_text)) title.append(hidelink) nav.append(title) text.append(poinav) links.append(text) nav.append(links) if 'no_poi_box' not in self.options: node.append(nav) node.append(collapsible) collapsible.append(hcontainer) numcols = len(contentnodes) for cont, offset, cnode, cwidth in contentnodes: # Bootstrap uses 12 unit grid if not cwidth: cwidth = int(12 / numcols) cnode['classes'] = ['col-sm-' + str(cwidth)] self.state.nested_parse(cont, offset, cnode, hcontainer) # poinav id needs to be added so that we can identify the node later when processing poinav['ids'].append(name) self.options['name'] = name self.add_name(node) collapsible['ids'].append(content_name) collapsible['classes'].extend([container_class, 'collapse']) node['classes'].extend(['poi']) if 'class' in self.options: node['classes'].extend(self.options['class']) title['classes'].extend(['poi-title']) links['classes'].extend(['poi-links']) if not 'hidden' in self.options: collapsible['classes'].extend(['in']) nav['classes'].extend([container_class]) # poi_info needs to be stored to env to be able to construct the # refuris later poi_info = { 'docname': env.docname, } if 'previous' in self.options: poi_info['previous'] = self.options['previous'] if 'next' in self.options: poi_info['next'] = self.options['next'] env.poi_all[name] = poi_info return [node]