def _make_section_main(self, obj=None, items=None, tag='main'): ''' make a section node - main ''' filename = self.options['name'] title = nodes.title(text=filename) section = nodes.section('', title, ids=[tag], names=[tag]) # add docstring if self.add_docstring: docs = [nodes.paragraph(text=i) for i in obj.__doc__.split('\n')] section += nodes.line_block('', *docs) # add the main toc lines = make_list(items, links=True) result = statemachine.ViewList() for line in lines: result.append(line, tag) self.state.nested_parse(result, 0, section) # add any version information if self.add_version: lines = _format_version(obj) result = statemachine.ViewList() for line in lines: result.append(line, tag) self.state.nested_parse(result, 0, section) return section
def add_description_node(self, anchor, description): description_node = nodes.line_block() description_node["classes"] = ["endpoint-card__description"] self.state.nested_parse(description, 0, description_node) anchor += [description_node]
def process_needlist(app, doctree, fromdocname): """ Replace all needlist nodes with a list of the collected needs. Augment each need with a backlink to the original location. """ env = app.builder.env for node in doctree.traverse(Needlist): if not app.config.needs_include_needs: # Ok, this is really dirty. # If we replace a node, docutils checks, if it will not lose any attributes. # But this is here the case, because we are using the attribute "ids" of a node. # However, I do not understand, why losing an attribute is such a big deal, so we delete everything # before docutils claims about it. for att in ('ids', 'names', 'classes', 'dupnames'): node[att] = [] node.replace_self([]) continue id = node.attributes["ids"][0] current_needfilter = env.need_all_needlists[id] all_needs = env.needs_all_needs content = [] all_needs = list(all_needs.values()) found_needs = procces_filters(all_needs, current_needfilter) line_block = nodes.line_block() for need_info in found_needs: para = nodes.line() description = "%s: %s" % (need_info["id"], need_info["title"]) if current_needfilter["show_status"] and need_info["status"] is not None: description += " (%s)" % need_info["status"] if current_needfilter["show_tags"] and need_info["tags"] is not None: description += " [%s]" % "; ".join(need_info["tags"]) title = nodes.Text(description, description) # Create a reference if not need_info["hide"]: ref = nodes.reference('', '') ref['refdocname'] = need_info['docname'] ref['refuri'] = app.builder.get_relative_uri( fromdocname, need_info['docname']) ref['refuri'] += '#' + need_info['target_node']['refid'] ref.append(title) para += ref else: para += title line_block.append(para) content.append(line_block) if len(content) == 0: content.append(no_needs_found_paragraph()) if current_needfilter["show_filters"]: content.append(used_filter_paragraph(current_needfilter)) node.replace_self(content)
def reference_group(name, rawtext, text, lineno, inliner, options={}, content=[]): path = inliner.document.current_source path = str(pathlib.Path(path).relative_to(DOCS_SRC)) _refs = REFERENCES.get(path, {}).get(text, []) if not _refs: return ([], []) container = nodes.enumerated_list() for ref in _refs: output = [ *ref.get("link", Null()).as_nodes(), *ref.get("section", Null()).as_nodes(), *ref.get("user", Null()).as_nodes(), *ref.get("license", Null()).as_nodes(), ] if Null() == (quote := ref.get("quote", Null())): message = nodes.paragraph() for node in output: message.append(node) else: message = nodes.line_block("", nodes.line("", "", *output), nodes.line( "", "", *quote.as_nodes(), )) container.append(nodes.list_item('', message))
def line_block(self, match, context, next_state): """First line of a line block.""" block = nodes.line_block() self.parent += block lineno = self.state_machine.abs_line_number() line, messages, blank_finish = self.line_block_line(match, lineno) block += line self.parent += messages if not blank_finish: offset = self.state_machine.line_offset + 1 # next line new_line_offset, blank_finish = self.nested_list_parse( self.state_machine.input_lines[offset:], input_offset=self.state_machine.abs_line_offset() + 1, node=block, initial_state='LineBlock', blank_finish=0) self.goto_line(new_line_offset) if not blank_finish: self.parent += self.reporter.warning( 'Line block ends without a blank line.', line=lineno+1) if len(block): if block[0].indent is None: block[0].indent = 0 self.nest_line_block_lines(block) raw = '\n'.join(['| %s' % child.rawsource for child in block.children]) block.rawsource = raw return [], next_state, []
def run(self): env = self.state.document.settings.env block_quote = nodes.line_block() block_quote['classes'].append('folders') node = nodes.bullet_list() block_quote.append(node) stack = [node] indents = [-1] for line in self.content: match = re.search('[-+] ', line) if match is None: break indent = match.start() node = nodes.list_item() text = line[match.end():] print(line[match.end():]) if indent <= indents[-1]: stack.pop() indents.pop() stack[-1].append(node) if line[match.start()] == '+': node.append(nodes.inline(text='� ' + text)) node['classes'].append('folder') children = nodes.bullet_list() node.append(children) stack.append(children) indents.append(indent) else: node.append(nodes.inline(text='🖹 ' + text)) node['classes'].append('file') return [block_quote]
def run(self): try: fields = self.future_fields.get(timeout=30) except Queue.Empty: return [self.state_machine.reporter.error( "Timed out while fetching fields related to action [%s]" % self.arguments[0] )] if fields is None: return [self.state_machine.reporter.warning( "Could not find any field related to the action [%s]" % self.arguments[0] )] whitelist = set(self.options.get('only', '').split()) return [nodes.field_list('', *( nodes.field('', nodes.field_name(text=v['string'] or k), nodes.field_body('', # keep help formatting around (e.g. newlines for lists) nodes.line_block('', *( nodes.line(text=line) for line in v['help'].split('\n') )) ) ) for k, v in fields.iteritems() # if there's a whitelist, only display whitelisted fields if not whitelist or k in whitelist # only display if there's a help text if v.get('help') ))]
def add_description_node(self, container, description, collapse, collapse_children): description_node = nodes.line_block() description_node["classes"] = ["parameter__description"] if collapse: description_node["classes"] += ["collapsed"] self.state.nested_parse(description, 0, description_node) # Traverse the parsed description to see if we have sub-parameters. sub_parameters = description_node.traverse(nodes.container, include_self=False) if len(sub_parameters): sub_parameter_container = nodes.container() sub_parameter_container["classes"] = ["parameter__children"] if not collapse_children: sub_parameter_container["classes"] += ["active"] # Move all sub-parameters into the new container. for sub_parameter in sub_parameters: # Skip sub-sub-parameters. if sub_parameter.parent is not description_node: continue description_node.remove(sub_parameter) sub_parameter_container.append(sub_parameter) # Add the 'Show child parameters' button. if collapse_children: button_label = "Show child parameters" button_classes = "parameter__children-button" else: button_label = "Hide child parameters" button_classes = "parameter__children-button active" sub_parameter_button = nodes.raw( button_label, '<p class="' + button_classes + '">' + '<a href="javascript:void(0)" data-handler="child-parameters"' + ' data-hide-label="Hide child parameters" data-show-label="Show child parameters">' + button_label + '</a>' + '</p>', format="html") description_node.append(sub_parameter_button) # Add the new container to the description. description_node.append(sub_parameter_container) container += [description_node]
def run(self): self.assert_has_content() block = nodes.line_block(classes=self.options.get("class", [])) node_list = [block] for line_text in self.content: text_nodes, messages = self.state.inline_text(line_text.strip(), self.lineno + self.content_offset) line = nodes.line(line_text, "", *text_nodes) if line_text.strip(): line.indent = len(line_text) - len(line_text.lstrip()) block += line node_list.extend(messages) self.content_offset += 1 self.state.nest_line_block_lines(block) return node_list
def new_workflow_entry_section(self, workflow, ids) -> nodes.section: self.logger.verbose("Generating entry for {}".format(workflow.name)) targetname = nodes.fully_normalize_name(workflow.name) workflow_item = nodes.section(ids=[ids], names=[targetname]) workflow_item.append(nodes.title(text=workflow.name, ids=[ids])) if "nodescription" not in self.options and workflow.description: description_block = nodes.line_block() for line in workflow.description.split("\n"): new_line = nodes.line(text=line) description_block += new_line workflow_item.append(description_block) return workflow_item
def nest_line_block_level (self, block, indent_level, indent_levels): """ Recursive part of nest_line_block_segment. """ last_indent = indent_levels[indent_level] line_block = nodes.line_block () while len (block): indent = block[0].indent if indent < last_indent: break # end recursion if indent > last_indent: line_block.append ( self.nest_line_block_level (block, indent_level + 1, indent_levels)) continue line_block.append (block.pop (0)) return line_block
def run(self): self.assert_has_content() block = nodes.line_block(classes=self.options.get('class', [])) node_list = [block] for line_text in self.content: text_nodes, messages = self.state.inline_text( line_text.strip(), self.lineno + self.content_offset) line = nodes.line(line_text, '', *text_nodes) if line_text.strip(): line.indent = len(line_text) - len(line_text.lstrip()) block += line node_list.extend(messages) self.content_offset += 1 self.state.nest_line_block_lines(block) return node_list
def visit_H2Node(self, node): self.h2Text = node.astext() self.h2Text = sphinxEncode(self.h2Text) strong = nodes.strong("") strong.children = node.children line = nodes.line("") line.append(strong) line_block = nodes.line_block("") line_block.append(line) node.children = [] node.append(line_block)
def nest_line_block_level(self, block, indent_level, indent_levels): """ Recursive part of nest_line_block_segment. """ last_indent = indent_levels[indent_level] line_block = nodes.line_block() while len(block): indent = block[0].indent if indent < last_indent: break # end recursion if indent > last_indent: line_block.append( self.nest_line_block_level(block, indent_level + 1, indent_levels)) continue line_block.append(block.pop(0)) return line_block
def make_row(data): row = nodes.row() for text in data: entry = nodes.entry() row += entry para = nodes.paragraph() entry += para if isinstance(text, list): lb = nodes.line_block() para += lb for t in text: line = nodes.line() lb += line line += nodes.Text(t) else: para += nodes.Text(text) return row
def _append_detailed_message(self, item, detailed_message): detailed_message = detailed_message.strip() style = self.options.get('detailed-message-style', None) if style == 'rst': node = nodes.Element() self.state.nested_parse( StringList(detailed_message.splitlines()), 0, node) item.extend(node.children) elif style == 'line': lines = detailed_message.splitlines() line_block = nodes.line_block() line_block.extend((nodes.line(text=line) for line in lines)) item.append(line_block) elif style == 'pre' or self.options.get('detailed-message-pre', False): item.append(nodes.literal_block(text=detailed_message)) else: item.append(nodes.paragraph(text=detailed_message))
def make_item(id, tags): name = extracters.get_post_title(id) link = f'https://codereview.meta.stackexchange.com/q/{id}/42401' post = Post(link, name, name) if not tags: inner = nodes.paragraph() inner.append(post) else: inner = nodes.line_block( '', nodes.line('', '', post), nodes.line( '', '', *(MTag(t) for t in tags), ) ) return nodes.list_item('', inner)
def run(self): config = self.state.document.settings.env.config model_name = self.arguments[0] optfields = self.options.get('fields') if not optfields: fields = _client.model(model_name).keys() else: fields = optfields.split(' ') l = [ x for x in fields if x not in ['create_uid', 'create_date', 'write_uid', 'write_date'] ] res1 = _client.execute(model_name, 'fields_get', l, context={'lang': config.odoo_lang}) res = OrderedDict() print('**************************', model_name) for a in l: res[a] = res1[a] classes = [config.odoodoc_fieldlistclass] if 'class' in self.options: classes.extend(self.options['class']) return [ nodes.field_list( '', *( nodes.field( '', nodes.field_name(text=v['string'] or k), nodes.field_body( '', # keep help formatting around (e.g. newlines for lists) nodes.line_block( '', *(nodes.line(text=line) for line in v['help'].split('\n'))))) for k, v in res.iteritems() # only display if there's a help text if v.get('help')), classes=classes, format='html') ]
def line_block(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine): if not content: warning = state_machine.reporter.warning( 'Content block expected for the "%s" directive; none found.' % name, nodes.literal_block(block_text, block_text), line=lineno) return [warning] block = nodes.line_block(classes=options.get('class', [])) node_list = [block] for line_text in content: text_nodes, messages = state.inline_text(line_text.strip(), lineno + content_offset) line = nodes.line(line_text, '', *text_nodes) if line_text.strip(): line.indent = len(line_text) - len(line_text.lstrip()) block += line node_list.extend(messages) content_offset += 1 state.nest_line_block_lines(block) return node_list
def __init__(self, options, from_verse = None, to_verse = None): self.options = options self.node_stack = [(nodes.block_quote(), 0)] # node, depth self.is_first = True self.show_label = False self.current_verse = 0 # TODO: Need to handle some psalms that have a 'verse 0' self.from_verse = from_verse if self.from_verse is not None and to_verse is None: self.to_verse = from_verse else: self.to_verse = to_verse if 'title' in options: title = nodes.Text(options['title']) line = nodes.line() line_block = nodes.line_block() line.append(title) if 'bold' in options: bold = nodes.strong() bold.append(line) line = bold line_block.append(line) self.node_stack[0][0].append(line_block)
def run(self): if self.env.app.builder.name != "man": self.arguments = ["fish-synopsis"] return CodeBlock.run(self) lexer = FishSynopsisLexer() result = nodes.line_block() for (start, tok, text) in lexer.get_tokens_unprocessed("\n".join(self.content)): if ( # Literal text. (tok in (Name.Function, Name.Constant) and not text.isupper()) or text.startswith( "-") # Literal option, even if it's uppercase. or tok in (Operator, Punctuation) or text == " ]" # Tiny hack: the closing bracket of the test(1) alias is a literal. ): node = nodes.strong(text=text) elif (tok in (Name.Constant, Name.Function) and text.isupper()): # Placeholder parameter. node = nodes.emphasis(text=text) else: # Grammar metacharacter or whitespace. node = nodes.inline(text=text) result.append(node) return [result]
def _update_stack(self, item, depth): if not self._verse_wanted(): return if self.is_first: self.is_first = False self._update_stack(nodes.line_block(), depth - 2) self._update_stack(nodes.line(), depth - 1) tos,tos_depth = self.node_stack[-1] #print("tos:",type(tos),tos, depth, tos_depth) #print('stk1:',self.node_stack) while depth <= tos_depth: del self.node_stack[-1] old_nodes = [tos] #print("old:",type(tos),tos, depth, tos_depth) tos,tos_depth = self.node_stack[-1] #print("pre:",type(tos),tos, depth, tos_depth) while not hasattr(tos, 'append'): del self.node_stack[-1] old_nodes.insert(0, tos) tos, tos_depth = self.node_stack[-1] #print("pre!:",type(tos),tos, depth, tos_depth) tos.extend(old_nodes) self.node_stack.append((item, depth))
def get_section(self, section): try: lines = self.layout["layout"][section] except KeyError: # Return nothing, if not specific configuration is given for layout section return [] # Needed for PDF/Latex output, where empty line_blocks raise exceptions during build if len(lines) == 0: return [] lines_container = nodes.line_block(classes=[f"needs_{section}"]) for line in lines: # line_block_node = nodes.line_block() line_node = nodes.line() line_parsed = self._parse(line) line_ready = self._func_replace(line_parsed) line_node += line_ready lines_container.append(line_node) return lines_container
def run(self): p = nodes.line_block(text=self.content) self.state.nested_parse(self.content, self.content_offset, p) content = self.create_rows(p.children[0].children) table = nodes.table(border=0, frame='void') tgroup = nodes.tgroup(cols=len(content)) table += tgroup for i in range(2): tgroup += nodes.colspec(colwidth=1) # thead = nodes.thead() # tgroup += thead # thead += self.create_table_row(header) tbody = nodes.tbody() tgroup += tbody for data_row in content: tbody += self.create_table_row(data_row) return [table]
def run(self): workflow = all_workflows.get(self.arguments[0]) if not workflow: valid_workflows = [w for w in all_workflows.keys()] self.warning(f"Unable to add {self.arguments[0]}, " f"Only known ones are {','.join(valid_workflows)}") return [] indexnode = addnodes.index(entries=[]) targetid = nodes.make_id("workflow-{}".format(workflow.name)) targetname = nodes.fully_normalize_name(workflow.name) section = nodes.section(names=[targetname], ids=[targetid]) if "notitle" not in self.options: new_title = nodes.title(workflow.name, text=workflow.name, ids=[targetid]) section.append(new_title) if "description" in self.options and workflow.description: description_block = nodes.line_block() for line in workflow.description.split("\n"): new_line = nodes.line(text=line) description_block += new_line section += description_block par = nodes.paragraph() self.state.nested_parse(self.content, self.content_offset, par) section += par self.add_name(section) indexnode['entries'].append( ('single', workflow.name, targetid, '', workflow.name[0])) section.append(indexnode) return [section]
def construct_meta(need_data, env): """ Constructs the node-structure for the status container :param need_data: need_info container :return: node """ hide_options = env.config.needs_hide_options if not isinstance(hide_options, list): raise SphinxError( 'Config parameter needs_hide_options must be of type list') node_meta = nodes.line_block(classes=['needs_meta']) # need parameters param_status = "status: " param_tags = "tags: " if need_data["status"] is not None and 'status' not in hide_options: status_line = nodes.line(classes=['status']) # node_status = nodes.line(param_status, param_status, classes=['status']) node_status = nodes.inline(param_status, param_status, classes=['status']) status_line.append(node_status) status_line.append( nodes.inline(need_data["status"], need_data["status"], classes=["needs-status", str(need_data['status'])])) node_meta.append(status_line) if need_data["tags"] and 'tags' not in hide_options: tag_line = nodes.line(classes=['tags']) # node_tags = nodes.line(param_tags, param_tags, classes=['tags']) node_tags = nodes.inline(param_tags, param_tags, classes=['tags']) tag_line.append(node_tags) for tag in need_data['tags']: # node_tags.append(nodes.inline(tag, tag, classes=["needs-tag", str(tag)])) # node_tags.append(nodes.inline(' ', ' ')) tag_line.append( nodes.emphasis(tag, tag, classes=["needs-tag", str(tag)])) tag_line.append(nodes.inline(" ", " ")) node_meta.append(tag_line) # Links incoming if need_data['links_back'] and 'links_back' not in hide_options: node_incoming_line = nodes.line(classes=['links', 'incoming']) prefix = "links incoming: " node_incoming_prefix = nodes.inline(prefix, prefix) node_incoming_line.append(node_incoming_prefix) node_incoming_links = Need_incoming(reftarget=need_data['id']) node_incoming_links.append( nodes.inline(need_data['id'], need_data['id'])) node_incoming_line.append(node_incoming_links) node_meta.append(node_incoming_line) # # Links outgoing if need_data['links'] and 'links' not in hide_options: node_outgoing_line = nodes.line(classes=['links', 'outgoing']) prefix = "links outgoing: " node_outgoing_prefix = nodes.inline(prefix, prefix) node_outgoing_line.append(node_outgoing_prefix) node_outgoing_links = Need_outgoing(reftarget=need_data['id']) node_outgoing_links.append( nodes.inline(need_data['id'], need_data['id'])) node_outgoing_line.append(node_outgoing_links) node_meta.append(node_outgoing_line) extra_options = getattr(env.config, 'needs_extra_options', {}) node_extra_options = [] for key, value in extra_options.items(): if key in hide_options: continue param_data = need_data[key] if param_data is None or not param_data: continue param_option = '{}: '.format(key) option_line = nodes.line(classes=['extra_option']) option_line.append( nodes.inline(param_option, param_option, classes=['extra_option'])) option_line.append( nodes.inline(param_data, param_data, classes=["needs-extra-option", str(key)])) node_extra_options.append(option_line) node_meta += node_extra_options global_options = getattr(env.config, 'needs_global_options', {}) node_global_options = [] for key, value in global_options.items(): # If a global option got locally overwritten, it must already part of extra_options. # In this skipp output, as this is done during extra_option handling if key in extra_options or key in hide_options: continue param_data = need_data[key] if param_data is None or not param_data: continue param_option = '{}: '.format(key) global_option_line = nodes.line(classes=['global_option']) global_option_line.append( nodes.inline(param_option, param_option, classes=['global_option'])) global_option_line.append( nodes.inline(param_data, param_data, classes=["needs-global-option", str(key)])) node_global_options.append(global_option_line) node_meta += node_global_options return node_meta
def process_needlist(app, doctree, fromdocname): """ Replace all needlist nodes with a list of the collected needs. Augment each need with a backlink to the original location. """ env = app.builder.env for node in doctree.traverse(Needlist): if not app.config.needs_include_needs: # Ok, this is really dirty. # If we replace a node, docutils checks, if it will not lose any attributes. # But this is here the case, because we are using the attribute "ids" of a node. # However, I do not understand, why losing an attribute is such a big deal, so we delete everything # before docutils claims about it. for att in ("ids", "names", "classes", "dupnames"): node[att] = [] node.replace_self([]) continue id = node.attributes["ids"][0] current_needfilter = env.need_all_needlists[id] all_needs = env.needs_all_needs content = [] all_needs = list(all_needs.values()) found_needs = process_filters(app, all_needs, current_needfilter) line_block = nodes.line_block() # Add lineno to node line_block.line = current_needfilter["lineno"] for need_info in found_needs: para = nodes.line() description = "{}: {}".format(need_info["id"], need_info["title"]) if current_needfilter["show_status"] and need_info["status"]: description += " (%s)" % need_info["status"] if current_needfilter["show_tags"] and need_info["tags"]: description += " [%s]" % "; ".join(need_info["tags"]) title = nodes.Text(description, description) # Create a reference if need_info["hide"]: para += title elif need_info["is_external"]: ref = nodes.reference("", "") ref["refuri"] = check_and_calc_base_url_rel_path( need_info["external_url"], fromdocname) ref["classes"].append(need_info["external_css"]) ref.append(title) para += ref else: ref = nodes.reference("", "") ref["refdocname"] = need_info["docname"] ref["refuri"] = app.builder.get_relative_uri( fromdocname, need_info["docname"]) ref["refuri"] += "#" + need_info["target_node"]["refid"] ref.append(title) para += ref line_block.append(para) content.append(line_block) if len(content) == 0: content.append(no_needs_found_paragraph()) if current_needfilter["show_filters"]: content.append(used_filter_paragraph(current_needfilter)) node.replace_self(content)
def _process_gradebook_nodes(app, doctree, docname): env = app.builder.env # Get the first element of the path to the current document. This defines the URL for the book. book_url = docname.split('/')[0] + '/' # Look for all gradebook nodes. for node in doctree.traverse(_GradebookNode): # Traverse the global TOC, only including files in the current book. The data structure created to walk the TOC: ``[ [docnames of level 0] [docnames of level 1] ... ]``. The data structure used to store the output: ``[ [level docname] ... ]``. The core algorithm: # # 1. Initialize data structures. toc = [[app.config.master_doc]] gradebooks = _get_interactive_questions(env).gradebooks # The gradebook should be empty -- verify this. if docname in gradebooks: raise SphinxError('{}: Multiple gradebook directives in one document is not allowed.'.format(env.doc2path(docname))) gradebook = gradebooks[docname] = [] printed_level = 0 # 2. While ``toc`` is not empty: while toc[0]: # 1. Set ``current_docname`` = (the first docname from the end of ``toc``). current_docname = toc[-1][0] # 2. If ``current_docname`` has questions, then append ``[level docname]`` taken from the ``toc[i][0]`` for ``i = printed_level ... end of toc``. if _has_questions(env, current_docname): for printed_level in range(printed_level, len(toc)): docname_to_print = toc[printed_level][0] gradebook.append([ printed_level, docname_to_print ]) printed_level += 1 # 3. If ``current_docname`` has children, append those in the current book to ``toc``. children = env.toctree_includes.get(current_docname, None) if children: children = [x for x in children if x.startswith(book_url)] if children: toc += [children] # Note that this document's content depends on the title in current_docname. Invoking ``env.note_dependency(current_docname)`` doesn't work -- there is no current document. The resulting error is:: # # File "e:\downloads\anaconda3\lib\site-packages\sphinx\environment.py", line 821, in docname # return self.temp_data['docname'] # # The code behind `env.note_dependency <http://www.sphinx-doc.org/en/stable/extdev/envapi.html#sphinx.environment.BuildEnvironment.note_dependency>`_ is ``self.dependencies.setdefault(self.docname, set()).add(filename)``, where ``self.docname`` returns the current docname. So, replace this with ``docname`` (passed to this function): env.dependencies.setdefault(docname, set()).add(env.doc2path(current_docname)) else: # Otherwise, remove ``current_docname`` from ``toc``. Find the next sibling, removing any parents found in the search for the next sibling. del toc[-1][0] while toc[0] and not toc[-1]: del toc[-1] del toc[-1][0] printed_level = min(printed_level, len(toc)) # Next, transform this list into HTML. It's too late to insert reST -- the parser is done. Instead, we need to insert nodes, which is more painful than straight HTML. html = ['<table border=0 style="align: center; width=500px;">'] line_block_node = nodes.line_block() for level, current_docname in gradebook: # Compute the appropriate hyperlink relative path. I'd prefer to insert a ``pending_xref`` node to have it do this, but the doctree is already resolved, so these can't be used. rp = os.path.relpath(os.path.dirname('/' + current_docname), start=os.path.dirname('/' + docname)) + '/' ext = _get_html_suffix(app) link = rp + os.path.basename(current_docname) + ext if _has_questions(env, current_docname): grade = '{{{{ grade("{}") }}}}'.format(current_docname + ext) else: grade = '' html += [ '<tr>' '<td><div style="margin-left: {}em;">'.format(level) + # Mimic how Sphinx inserts ``:doc:`` links using ``class`` and a ``span``. '<a class="reference internal" href="{}"><span class="doc">{}</span></a></div></td>'.format(link, env.titles[current_docname].astext()) + '<td>{}</td>'.format(grade) + '</tr>' ] html += ['</table>'] raw_node = nodes.raw('gradebook', utils.unescape(''.join(html), 1), format='html') node.replace_self(raw_node)
def process_needfilters(app, doctree, fromdocname): # Replace all needlist nodes with a list of the collected needs. # Augment each need with a backlink to the original location. env = app.builder.env # NEEDFILTER for node in doctree.traverse(Needfilter): if not app.config.needs_include_needs: # Ok, this is really dirty. # If we replace a node, docutils checks, if it will not lose any attributes. # But this is here the case, because we are using the attribute "ids" of a node. # However, I do not understand, why losing an attribute is such a big deal, so we delete everything # before docutils claims about it. for att in ('ids', 'names', 'classes', 'dupnames'): node[att] = [] node.replace_self([]) continue id = node.attributes["ids"][0] current_needfilter = env.need_all_needfilters[id] all_needs = env.needs_all_needs if current_needfilter["layout"] == "list": content = [] elif current_needfilter["layout"] == "diagram": content = [] try: if "sphinxcontrib.plantuml" not in app.config.extensions: raise ImportError from sphinxcontrib.plantuml import plantuml except ImportError: content = nodes.error() para = nodes.paragraph() text = nodes.Text("PlantUML is not available!", "PlantUML is not available!") para += text content.append(para) node.replace_self(content) continue plantuml_block_text = ".. plantuml::\n" \ "\n" \ " @startuml" \ " @enduml" puml_node = plantuml(plantuml_block_text, **dict()) puml_node["uml"] = "@startuml\n" puml_connections = "" elif current_needfilter["layout"] == "table": content = nodes.table() tgroup = nodes.tgroup() id_colspec = nodes.colspec(colwidth=5) title_colspec = nodes.colspec(colwidth=15) type_colspec = nodes.colspec(colwidth=5) status_colspec = nodes.colspec(colwidth=5) links_colspec = nodes.colspec(colwidth=5) tags_colspec = nodes.colspec(colwidth=5) tgroup += [ id_colspec, title_colspec, type_colspec, status_colspec, links_colspec, tags_colspec ] tgroup += nodes.thead( '', nodes.row('', nodes.entry('', nodes.paragraph('', 'ID')), nodes.entry('', nodes.paragraph('', 'Title')), nodes.entry('', nodes.paragraph('', 'Type')), nodes.entry('', nodes.paragraph('', 'Status')), nodes.entry('', nodes.paragraph('', 'Links')), nodes.entry('', nodes.paragraph('', 'Tags')))) tbody = nodes.tbody() tgroup += tbody content += tgroup all_needs = list(all_needs.values()) if current_needfilter["sort_by"] is not None: if current_needfilter["sort_by"] == "id": all_needs = sorted(all_needs, key=lambda node: node["id"]) elif current_needfilter["sort_by"] == "status": all_needs = sorted(all_needs, key=status_sorter) found_needs = procces_filters(all_needs, current_needfilter) line_block = nodes.line_block() for need_info in found_needs: if current_needfilter["layout"] == "list": para = nodes.line() description = "%s: %s" % (need_info["id"], need_info["title"]) if current_needfilter["show_status"] and need_info[ "status"] is not None: description += " (%s)" % need_info["status"] if current_needfilter["show_tags"] and need_info[ "tags"] is not None: description += " [%s]" % "; ".join(need_info["tags"]) title = nodes.Text(description, description) # Create a reference if not need_info["hide"]: ref = nodes.reference('', '') ref['refdocname'] = need_info['docname'] ref['refuri'] = app.builder.get_relative_uri( fromdocname, need_info['docname']) ref['refuri'] += '#' + need_info['target_node']['refid'] ref.append(title) para += ref else: para += title line_block.append(para) elif current_needfilter["layout"] == "table": row = nodes.row() row += row_col_maker(app, fromdocname, env.needs_all_needs, need_info, "id", make_ref=True) row += row_col_maker(app, fromdocname, env.needs_all_needs, need_info, "title") row += row_col_maker(app, fromdocname, env.needs_all_needs, need_info, "type_name") row += row_col_maker(app, fromdocname, env.needs_all_needs, need_info, "status") row += row_col_maker(app, fromdocname, env.needs_all_needs, need_info, "links", ref_lookup=True) row += row_col_maker(app, fromdocname, env.needs_all_needs, need_info, "tags") tbody += row elif current_needfilter["layout"] == "diagram": # Link calculation # All links we can get from docutils functions will be relative. # But the generated link in the svg will be relative to the svg-file location # (e.g. server.com/docs/_images/sqwxo499cnq329439dfjne.svg) # and not to current documentation. Therefore we need to add ../ to get out of the _image folder. try: link = "../" + app.builder.get_target_uri(need_info['docname']) \ + "?highlight={0}".format(urlParse(need_info['title'])) \ + "#" \ + need_info['target_node']['refid'] \ # Gets mostly called during latex generation except NoUri: link = "" diagram_template = Template(env.config.needs_diagram_template) node_text = diagram_template.render(**need_info) puml_node[ "uml"] += '{style} "{node_text}" as {id} [[{link}]] {color}\n'.format( id=need_info["id"], node_text=node_text, link=link, color=need_info["type_color"], style=need_info["type_style"]) for link in need_info["links"]: puml_connections += '{id} --> {link}\n'.format( id=need_info["id"], link=link) if current_needfilter["layout"] == "list": content.append(line_block) if current_needfilter["layout"] == "diagram": puml_node["uml"] += puml_connections # Create a legend if current_needfilter["show_legend"]: puml_node["uml"] += "legend\n" puml_node["uml"] += "|= Color |= Type |\n" for need in app.config.needs_types: puml_node[ "uml"] += "|<back:{color}> {color} </back>| {name} |\n".format( color=need["color"], name=need["title"]) puml_node["uml"] += "endlegend\n" puml_node["uml"] += "@enduml" puml_node["incdir"] = os.path.dirname( current_needfilter["docname"]) puml_node["filename"] = os.path.split( current_needfilter["docname"])[1] # Needed for plantuml >= 0.9 content.append(puml_node) if len(content) == 0: nothing_found = "No needs passed the filters" para = nodes.line() nothing_found_node = nodes.Text(nothing_found, nothing_found) para += nothing_found_node content.append(para) if current_needfilter["show_filters"]: para = nodes.paragraph() filter_text = "Used filter:" filter_text += " status(%s)" % " OR ".join( current_needfilter["status"]) if len( current_needfilter["status"]) > 0 else "" if len(current_needfilter["status"]) > 0 and len( current_needfilter["tags"]) > 0: filter_text += " AND " filter_text += " tags(%s)" % " OR ".join( current_needfilter["tags"]) if len( current_needfilter["tags"]) > 0 else "" if (len(current_needfilter["status"]) > 0 or len(current_needfilter["tags"]) > 0) and len( current_needfilter["types"]) > 0: filter_text += " AND " filter_text += " types(%s)" % " OR ".join( current_needfilter["types"]) if len( current_needfilter["types"]) > 0 else "" filter_node = nodes.emphasis(filter_text, filter_text) para += filter_node content.append(para) node.replace_self(content)
def div_p(self, elem, depth): #print (' '*depth, depth,'<p>') self._update_stack(nodes.line_block(), depth - 1) node = nodes.line() self._update_stack(node, depth)
def run(self): env = self.state.document.settings.env extcode_config = env.app.config.extcode if not extcode_config: if all(opt not in self.options for opt in self.extra_option_spec): return super(ExtCode, self).run() # nothing to do special rendered_block = self.options.get('rendered-block', extcode_config.get('rendered-block')) line_annotations = {} annotations = self.options.get('annotations', []) annotationsmap = dict((k.astext(), v) for k, v in annotations) for i, c in enumerate(self.content): match = annotation_matcher(c) if match: self.content[i], label = match.groups() if label in annotationsmap: line_annotations[i] = (label, annotationsmap[label]) else: #TODO: warning line_annotations[i] = (label, None) # get literal from modified self.content literal = super(ExtCode, self).run()[0] # line_annotations attribute will be used for writer (not yet) literal['line_annotations'] = line_annotations wrapper = extcode(classes=['extcode']) set_source_info(self, wrapper) #check: can parse rst? and partial build? try: partial_doc = sandbox_rst_parser(u'\n'.join(self.content), env.doc2path(env.docname), env.settings) partial_out = sandbox_partial_builder(partial_doc, env) except Exception as e: env.warn(env.docname, u'extcode: partial build failed: %s' % str(e), lineno=self.lineno) partial_doc = None partial_out = None if literal['language'] == 'rst' and rendered_block: wrapper['classes'].append('extcode-layout-' + rendered_block) rendered = nodes.container() set_source_info(self, rendered) only_html = addnodes.only(expr='html') set_source_info(self, only_html) only_html += nodes.raw(partial_out, partial_out, format='html', classes=['extcode-rendered']) rendered += only_html if 'rendered-image' in self.options: only_xml = addnodes.only(expr='xml') set_source_info(self, only_xml) only_xml += nodes.image(self.options['rendered-image'], uri=self.options['rendered-image']) rendered += only_xml #FIXME: need translation support make_text = lambda t: nodes.inline(t, t) if rendered_block == 'horizontal': table = build_table( [[make_text('literal'), make_text('rendered')], [literal, rendered]], [1, 1], head_rows=1, attrs={'classes': ['extcode-layout']}) table.setdefault('classes', []).append('extcode-layout') wrapper.append(table) elif rendered_block == 'vertical': table = build_table([[make_text('literal'), literal], [make_text('rendered'), rendered]], [2, 8], stub_columns=1, attrs={'classes': ['extcode-layout']}) table.setdefault('classes', []).append('extcode-layout') wrapper.append(table) else: # toggle, tab wrapper.append(literal) wrapper.append(rendered) else: wrapper.append(literal) if line_annotations and 'annotate-inline' in self.options: prefix = '... ' #TODO prefixi customization contents = [] for i in range(0, len(self.content)): label, value = line_annotations.get(i, ('', None)) line = nodes.line() if label and value: #FIXME: label and explanation need translation support abbr = nodes.abbreviation( label, label ) #TODO: label customization (i.e. render with number) abbr['explanation'] = value.astext() line.append(nodes.inline(prefix, prefix)) line.append(abbr) elif label: line.append(nodes.inline(prefix, prefix)) line.append(nodes.Text(label, label)) contents.append(line) overlay = nodes.line_block(classes=['extcode-overlay']) set_source_info(self, overlay) overlay.extend(contents) wrapper.append(overlay) if annotations and 'annotate-block' in self.options: annotations['classes'] = ['extcode-annotations'] set_source_info(self, annotations) wrapper.append(annotations) return [wrapper]
targetnode = nodes.target('', '', ids=[targetid]) targetnode['classes'] = ['epigraph'] node = quote_node() node += nodes.block_quote( '', nodes.paragraph('', '\n'.join(self.content), classes=['text'])) #state.nested_parse(self.content, self.content_offset, node) for element in node: if isinstance(element, nodes.block_quote): element['classes'] += ['epigraph'] signode = [nodes.attribution('--', '--')] # Embed all components within attributions siglb = nodes.line_block('') # Pre-format some if 'date' in options: options['date'] = '[%(date)s]' % options if 'source' in options: options['source'] = 'Source: %(source)s' % options for el in ['author', 'date', 'affiliation', 'source']: if el in options: siglb += [nodes.inline('', ' '+options[el], classes=[el])] signode[0].extend(siglb) node[0].extend(signode) node.line = self.lineno # tune up options _prep_tags(self.options) node.options = options return [targetnode] + [node]