def generate_document_node(node, file): """ Generates the HTML code for heading node. :param sdoc.sdoc2.node.DocumentNode.DocumentNode node: The document node. :param file file: The output file. """ file.write('<div class="sdoc-document-title-outer">') if node.title_node_id: title_node = in_scope(node.title_node_id) file.write(Html.generate_element('h1', {}, title_node.argument)) out_scope(title_node) file.write('<div class="sdoc-document-title-inner">') if node.date_node_id: date_node = in_scope(node.date_node_id) if date_node.argument: file.write(Html.generate_element('span', {'class': 'sdoc-document-date'}, date_node.argument)) out_scope(date_node) if node.version_node_id: version_node = in_scope(node.version_node_id) if version_node.argument: file.write(Html.generate_element('span', {'class': 'sdoc-document-version'}, version_node.argument)) out_scope(version_node) file.write('</div>') file.write('</div>')
def generate_document_node(node: DocumentNode, file: Any) -> None: """ Generates the HTML code for heading node. :param DocumentNode node: The document node. :param any file: The output file. """ file.write('<div class="sdoc-document-title-outer">') if node.title_node_id: title_node = in_scope(node.title_node_id) file.write(Html.generate_element('h1', {}, title_node.argument)) out_scope(title_node) file.write('<div class="sdoc-document-title-inner">') if node.date_node_id: date_node = in_scope(node.date_node_id) if date_node.argument: file.write( Html.generate_element('span', {'class': 'sdoc-document-date'}, date_node.argument)) out_scope(date_node) if node.version_node_id: version_node = in_scope(node.version_node_id) if version_node.argument: file.write( Html.generate_element('span', {'class': 'sdoc-document-version'}, version_node.argument)) out_scope(version_node) file.write('</div>') file.write('</div>')
def test_numbering(self): """ Runs all test cases in the test/enumeration directory. """ test_file_names = glob.glob( os.path.dirname(os.path.abspath(__file__)) + "/enumeration/*.sdoc") config_path = glob.glob( os.path.dirname(os.path.abspath(__file__)) + "/enumeration/sdoc.cfg") for test_file_name in sorted(test_file_names): with self.subTest(test_file_name=test_file_name): pre, ext = os.path.splitext(test_file_name) csv_file_name = pre + '.csv' application = Application() application.add(SDoc2Command()) command = application.find('sdoc2') command_tester = CommandTester(command) command_tester.execute([('command', command.get_name()), ('config.cfg', config_path), ('main.sdoc2', test_file_name)]) root = in_scope(1) sdoc2.node_store.number_numerable() numbers = root.get_enumerated_items() actual = self.create_list_of_items(numbers) expected = self.csv_to_tuple(csv_file_name) self.assertEqual(expected, actual)
def prepare_content_tree(self): """ Method which checks if all child nodes is instance of sdoc.sdoc2.node.ItemNode.ItemNode. If not, removes from child node list and from node store. """ obsolete_node_ids = [] for node_id in self.child_nodes: node = in_scope(node_id) if isinstance(node, TextNode): # Ignore text nodes with only whitespace silently. if re.sub(r'\s+', '', node.argument) != '': # This text node contains more than only whitespace. node_store.error("Unexpected text '{0}'".format(node.argument), node) obsolete_node_ids.append(node_id) elif not isinstance(node, ItemNode): # An itemize node can have only item nodes as direct child nodes. node_store.error("Node: id:{0!s}, {1!s} is not instance of 'ItemNode'".format(str(node.id), node.name), node) obsolete_node_ids.append(node_id) out_scope(node) self._remove_child_nodes(obsolete_node_ids)
def modify_label_list(self): """ Creates label list for each heading node, and for node_store. Removes label nodes from child list. """ obsolete_node_ids = [] for node_id in self.child_nodes: node = in_scope(node_id) if node.get_command() == 'label': # Appending in Node labels list. self.labels.append(node.id) self.append_label_list_in_node_store(node) if self.get_option_value('number'): label_arg = self.get_option_value('number') title_attribute = self.argument else: label_arg = self.argument title_attribute = None node_store.labels[node.argument] = {'argument': label_arg, 'title': title_attribute} # Removing node from child nodes. obsolete_node_ids.append(node.id) node.parse_labels() out_scope(node) self._remove_child_nodes(obsolete_node_ids)
def get_enumerated_items(self): """ Returns a list with a tuple with command and number of enumerated child nodes. This method is intended for unit test only. :rtype: list[(str,str)] """ items = list() # First append the enumeration of this node (if any). if 'number' in self._options: items.append((self.get_command(), self._options['number'], self._argument)) # Second append the enumeration of child nodes (if any). for node_id in self.child_nodes: node = in_scope(node_id) tmp = node.get_enumerated_items() if tmp: items.append(tmp) out_scope(node) return items
def test_numbering(self): """ Runs all test cases in the test/enumeration directory. """ test_file_names = glob.glob(os.path.dirname(os.path.abspath(__file__)) + "/enumeration/*.sdoc") config_path = glob.glob(os.path.dirname(os.path.abspath(__file__)) + "/enumeration/sdoc.cfg") for test_file_name in sorted(test_file_names): with self.subTest(test_file_name=test_file_name): pre, ext = os.path.splitext(test_file_name) csv_file_name = pre + '.csv' application = Application() application.add(SDoc2Command()) command = application.find('sdoc2') command_tester = CommandTester(command) command_tester.execute([('command', command.get_name()), ('config.cfg', config_path), ('main.sdoc2', test_file_name)]) root = in_scope(1) sdoc2.node_store.number_numerable() numbers = root.get_enumerated_items() actual = self.create_list_of_items(numbers) expected = self.csv_to_tuple(csv_file_name) self.assertEqual(expected, actual)
def set_id_heading_node(self): """ Sets id to heading node. (Argument of first label) """ node = in_scope(self.labels[0]) self._options['id'] = node.argument out_scope(node)
def prepare_content_tree(self) -> None: """ Method which checks if all child nodes is instance of sdoc.sdoc2.node.ItemNode.ItemNode. If not, removes from child node list and from node store. """ obsolete_node_ids = [] for node_id in self.child_nodes: node = in_scope(node_id) if isinstance(node, TextNode): # Ignore text nodes with only whitespace silently. if re.sub(r'\s+', '', node.argument) != '': # This text node contains more than only whitespace. node_store.error( "Unexpected text '{0}'".format(node.argument), node) obsolete_node_ids.append(node_id) elif not isinstance(node, ItemNode): # An itemize node can have only item nodes as direct child nodes. node_store.error( "Node: id:{0!s}, {1!s} is not instance of 'ItemNode'". format(str(node.id), node.name), node) obsolete_node_ids.append(node_id) out_scope(node) self._remove_child_nodes(obsolete_node_ids)
def set_id_heading_node(self) -> None: """ Sets id to heading node. (Argument of first label) """ node = in_scope(self.labels[0]) self._options['id'] = node.argument out_scope(node)
def modify_label_list(self) -> None: """ Creates label list for each heading node, and for node_store. Removes label nodes from child list. """ obsolete_node_ids = [] for node_id in self.child_nodes: node = in_scope(node_id) if node.get_command() == 'label': # Appending in Node labels list. self.labels.append(node.id) self.append_label_list_in_node_store(node) if self.get_option_value('number'): label_arg = self.get_option_value('number') title_attribute = self.argument else: label_arg = self.argument title_attribute = None node_store.labels[node.argument] = {'argument': label_arg, 'title': title_attribute} # Removing node from child nodes. obsolete_node_ids.append(node.id) node.parse_labels() out_scope(node) self._remove_child_nodes(obsolete_node_ids)
def prepare_content_tree(self): """ Prepares this node for further processing. """ for node_id in self.child_nodes: node = in_scope(node_id) node.prepare_content_tree() out_scope(node)
def prepare_content_tree(self) -> None: """ Prepares this node for further processing. """ for node_id in self.child_nodes: node = in_scope(node_id) node.prepare_content_tree() out_scope(node)
def number(self, numbers): """ Numbers all numerable nodes such as chapters, sections, figures, and, items. :param numbers: The current numbers. """ for node_id in self.child_nodes: node = in_scope(node_id) node.number(numbers) out_scope(node)
def number(self, numbers: Dict[str, str]) -> None: """ Numbers all numerable nodes such as chapters, sections, figures, and, items. :param dict[str,str] numbers: The current numbers. """ for node_id in self.child_nodes: node = in_scope(node_id) node.number(numbers) out_scope(node)
def prepare_content_tree(self) -> None: """ Prepares this node for further processing. """ for node_id in self.child_nodes: node = in_scope(node_id) node.prepare_content_tree() self.__set_document_info(node) out_scope(node) self.__remove_document_info_nodes()
def prepare_content_tree(self): """ Prepares this node for further processing. """ for node_id in self.child_nodes: node = in_scope(node_id) node.prepare_content_tree() self.__set_document_info(node) out_scope(node) self.__remove_document_info_nodes()
def generate(self, node, file): """ Generates the representation of a node in the requested output format. :param sdoc.sdoc2.node.Node.Node node: The node for which the output must be generated. :param file file: The output file. """ for node_id in node.child_nodes: child_node = in_scope(node_id) formatter = node_store.create_formatter(self._io, child_node.get_command(), self) formatter.generate(child_node, file) out_scope(child_node)
def print_info(self, level): """ Temp function for development. :param int level: the level of block commands. """ self.io.writeln("{0!s}{1:4d} {2!s}".format(' ' * 4 * level, self.id, self.name)) for node_id in self.child_nodes: node = in_scope(node_id) node.print_info(level + 1) out_scope(node)
def print_info(self, level: int) -> None: """ Temp function for development. :param int level: the level of block commands. """ self.io.writeln("{0!s}{1:4d} {2!s}".format(' ' * 4 * level, self.id, self.name)) for node_id in self.child_nodes: node = in_scope(node_id) node.print_info(level + 1) out_scope(node)
def prepare_content_tree(self): """ Prepares this node for further processing. """ for node_id in self.child_nodes: node = in_scope(node_id) if isinstance(node, CaptionNode): self.caption = node.argument if isinstance(node, LabelNode): self.setup_label(node) out_scope(node)
def __check_document_info(info_node_current, info_node_new): """ Checks if a document info node has been set already. If so, an error will be logged. :param int|None info_node_current: The current document info node (i.e. a property of the document). :param sdoc.sdoc2.node.Node.Node info_node_new: The (new) document info node. """ if info_node_current: node = in_scope(info_node_current) position = node.position out_scope(node) NodeStore.error("Document info {0} can be specified only once. Previous definition at {1}.".format( info_node_new.name, str(position)), info_node_new)
def generate(self, node: Node, file: Any) -> None: """ Generates the representation of a node in the requested output format. :param Node node: The node for which the output must be generated. :param any file: The output file. """ for node_id in node.child_nodes: child_node = in_scope(node_id) formatter = node_store.create_formatter(self._io, child_node.get_command(), self) formatter.generate(child_node, file) out_scope(child_node)
def __check_document_info(info_node_current: Optional[int], info_node_new: Node) -> None: """ Checks if a document info node has been set already. If so, an error will be logged. :param int|None info_node_current: The current document info node (i.e. a property of the document). :param Node info_node_new: The (new) document info node. """ if info_node_current: node = in_scope(info_node_current) position = node.position out_scope(node) NodeStore.error( "Document info {0} can be specified only once. Previous definition at {1}." .format(info_node_new.name, str(position)), info_node_new)
def prune_whitespace(self): """ Removes spaces from end of a paragraph. """ first = self.child_nodes[0] last = self.child_nodes[-1] for node_id in self.child_nodes: node = in_scope(node_id) if isinstance(node, TextNode): if node.id == first: node.prune_whitespace(leading=True) if node.id == last: node.prune_whitespace(trailing=True) if node.id != last and node.id != first: node.prune_whitespace() out_scope(node)
def prune_whitespace(self) -> None: """ Removes spaces from end of a paragraph. """ first = self.child_nodes[0] last = self.child_nodes[-1] for node_id in self.child_nodes: node = in_scope(node_id) if isinstance(node, TextNode): if node.id == first: node.prune_whitespace(leading=True) if node.id == last: node.prune_whitespace(trailing=True) if node.id != last and node.id != first: node.prune_whitespace() out_scope(node)
def split_text_nodes(self): """ Replaces single text nodes that contains a paragraph separator (i.e. a double new line) with multiple text nodes without paragraph separator. """ new_child_nodes = [] for node_id in self.child_nodes: node = in_scope(node_id) if isinstance(node, TextNode): list_ids = node.split_by_paragraph() for ids in list_ids: new_child_nodes.append(ids) else: new_child_nodes.append(node.id) out_scope(node) self.child_nodes = new_child_nodes
def split_text_nodes(self) -> None: """ Replaces single text nodes that contains a paragraph separator (i.e. a double new line) with multiple text nodes without paragraph separator. """ new_child_nodes = [] for node_id in self.child_nodes: node = in_scope(node_id) if isinstance(node, TextNode): list_ids = node.split_by_paragraph() for ids in list_ids: new_child_nodes.append(ids) else: new_child_nodes.append(node.id) out_scope(node) self.child_nodes = new_child_nodes
def create_paragraphs(self) -> None: """ Create paragraph nodes. A paragraph consists of phrasing nodes only. Each continuous slice of phrasing child nodes is move to a paragraph node. """ new_child_nodes = [] paragraph_node = None for node_id in self.child_nodes: node = in_scope(node_id) if node.is_phrasing(): if not paragraph_node: paragraph_node = sdoc.sdoc2.node_store.create_inline_node( 'paragraph') new_child_nodes.append(paragraph_node.id) paragraph_node.append_child_node(node) else: if paragraph_node: paragraph_node.prune_whitespace() sdoc.sdoc2.node_store.store_node(paragraph_node) paragraph_node = None # End paragraph nodes are created temporary to separate paragraphs in a flat list of (text) node. There # role ae replaced by the content hierarchy now. So, we must no store end paragraph nodes. if not isinstance(node, EndParagraphNode): new_child_nodes.append(node.id) out_scope(node) if paragraph_node: paragraph_node.prune_whitespace() sdoc.sdoc2.node_store.store_node(paragraph_node) # paragraph_node = None # Setting child nodes. self.child_nodes = new_child_nodes
def create_paragraphs(self): """ Create paragraph nodes. A paragraph consists of phrasing nodes only. Each continuous slice of phrasing child nodes is move to a paragraph node. """ new_child_nodes = [] paragraph_node = None for node_id in self.child_nodes: node = in_scope(node_id) if node.is_phrasing(): if not paragraph_node: paragraph_node = sdoc.sdoc2.node_store.create_inline_node('paragraph') new_child_nodes.append(paragraph_node.id) paragraph_node.append_child_node(node) else: if paragraph_node: paragraph_node.prune_whitespace() sdoc.sdoc2.node_store.store_node(paragraph_node) paragraph_node = None # End paragraph nodes are created temporary to separate paragraphs in a flat list of (text) node. There # role ae replaced by the content hierarchy now. So, we must no store end paragraph nodes. if not isinstance(node, EndParagraphNode): new_child_nodes.append(node.id) out_scope(node) if paragraph_node: paragraph_node.prune_whitespace() sdoc.sdoc2.node_store.store_node(paragraph_node) # paragraph_node = None # Setting child nodes. self.child_nodes = new_child_nodes
def get_enumerated_items(self) -> List[Union[Tuple[str, str, str], List[Tuple[str, str]]]]: """ Returns a list with a tuple with command and number of enumerated child nodes. This method is intended for unit test only. """ items = list() # First append the enumeration of this node (if any). if 'number' in self._options: items.append((self.get_command(), self._options['number'], self._argument)) # Second append the enumeration of child nodes (if any). for node_id in self.child_nodes: node = in_scope(node_id) tmp = node.get_enumerated_items() if tmp: items.append(tmp) out_scope(node) return items
def prepare_content_tree(self): """ Prepares this node for further processing. """ table_nodes = [] for node_id in self.child_nodes: node = in_scope(node_id) if isinstance(node, LabelNode): self.setup_label(node) elif isinstance(node, CaptionNode): self.caption = node.argument else: table_nodes.append(node) node.prepare_content_tree() out_scope(node) self.generate_table(table_nodes)
def change_ref_argument(self) -> None: """ Changes reference argument on number of depending heading node. """ for node_id in self.child_nodes: node = in_scope(node_id) if node.get_command() == 'ref': if node.argument in node_store.labels: node.set_option_value('href', '#{0}'.format(node.argument)) if node_store.labels[node.argument]['title']: node.set_option_value('title', node_store.labels[node.argument]['title']) node.text = node_store.labels[node.argument]['argument'] else: node_store.error("Label '{}' not found".format(node.argument), node) node.change_ref_argument() out_scope(node)
def change_ref_argument(self): """ Changes reference argument on number of depending heading node. """ for node_id in self.child_nodes: node = in_scope(node_id) if node.get_command() == 'ref': if node.argument in node_store.labels: node.set_option_value('href', '#{0}'.format(node.argument)) if node_store.labels[node.argument]['title']: node.set_option_value('title', node_store.labels[node.argument]['title']) node.text = node_store.labels[node.argument]['argument'] else: node_store.error("Label '{}' not found".format(node.argument), node) node.change_ref_argument() out_scope(node)
def prepare_content_tree(self): """ Method which checks if all child nodes is phrasing. """ first = self.child_nodes[0] last = self.child_nodes[-1] for node_id in self.child_nodes: node = in_scope(node_id) if isinstance(node, TextNode): if node_id == first: node.prune_whitespace(leading=True) elif node_id == last: node.prune_whitespace(trailing=True) elif node_id == first and node_id == last: node.prune_whitespace(leading=True, trailing=True) # if not node.is_phrasing(): # raise RuntimeError("Node: id:%s, %s is not phrasing" % (str(node.id), node.name)) out_scope(node)
def prepare_content_tree(self) -> None: """ Method which checks if all child nodes is phrasing. """ first = self.child_nodes[0] last = self.child_nodes[-1] for node_id in self.child_nodes: node = in_scope(node_id) if isinstance(node, TextNode): if node_id == first: node.prune_whitespace(leading=True) elif node_id == last: node.prune_whitespace(trailing=True) elif node_id == first and node_id == last: node.prune_whitespace(leading=True, trailing=True) # if not node.is_phrasing(): # raise RuntimeError("Node: id:%s, %s is not phrasing" % (str(node.id), node.name)) out_scope(node)