diff --git a/spip2md/__init__.py b/spip2md/__init__.py index 209d5af..3902f25 100644 --- a/spip2md/__init__.py +++ b/spip2md/__init__.py @@ -6,39 +6,12 @@ from shutil import rmtree from spip2md.config import CFG from spip2md.database import DB -from spip2md.regexmap import SPECIAL_OUTPUT from spip2md.spipobjects import RootRubrique, Rubrique - -# Define styles -BOLD = 1 # Bold -ITALIC = 3 # Italic -UNDER = 4 # Underline -# Define colors -RED = 91 # Red -GREEN = 92 # Green -YELLOW = 93 # Yellow -BLUE = 94 # Blue -C0 = 95 # Color -C1 = 96 # Color -C2 = 96 # Color +from spip2md.style import BOLD, esc -# Terminal escape sequence -def esc(*args: int) -> str: - if len(args) == 0: - params: str = "0;" # Defaults to reset - else: - params: str = "" - # Build a string from args, that will be stripped from its trailing ; - for a in args: - params += str(a) + ";" - # Base terminal escape sequence that needs to be closed by "m" - return "\033[" + params[:-1] + "m" - - -# Print one root section list output correctly -# sys.setrecursionlimit(2000) -def print_output( +# Count on outputted tree +def count_output( tree: list[str | list[str | list]], indent: str = " ", depth: int = -1, @@ -47,15 +20,11 @@ def print_output( ) -> tuple[int, int]: for sub in tree: if type(sub) == list: - branches, leaves = print_output( + branches, leaves = count_output( sub, indent, depth + 1, branches + 1, leaves ) elif type(sub) == str: leaves += 1 - # Highlight special elements (in red for the moment) - for elmnt in SPECIAL_OUTPUT: - sub = elmnt.sub(esc(BOLD, GREEN) + r"\1" + esc(), sub) - print(indent * depth + sub) return (branches, leaves) @@ -84,12 +53,13 @@ def main(*argv): # Get the virtual id=0 section root: Rubrique = RootRubrique() - # Write everything & print the output human-readably - branches, leaves = print_output(root.write_tree(CFG.output_dir)) + # Write everything while printing the output human-readably + branches, leaves = count_output(root.write_tree(CFG.output_dir)) # End, summary message print( f""" -Exported a total of {leaves} Markdown files, stored into {branches} directories""" +Exported a total of {esc(BOLD)}{leaves}{esc()} Markdown files, \ +stored into {esc(BOLD)}{branches}{esc()} directories""" ) # print() # Break line between export & unknown characters warning diff --git a/spip2md/regexmap.py b/spip2md/regexmap.py index 8fe481e..d8f2b4c 100644 --- a/spip2md/regexmap.py +++ b/spip2md/regexmap.py @@ -260,3 +260,10 @@ SPECIAL_OUTPUT = ( compile(r"(?<= )(->)(?= )"), # Arrow compile(r"(?<=^Exporting )([0-9]+?)(?= )"), # Total ) + +# Warning elements in terminal output to highlight +WARNING_OUTPUT = ( + compile(r"(ERROR)"), # ERROR + compile(r"(MISSING NAME)"), # MISSING NAME + compile(r"(NOT FOUND)"), # NOT FOUND +) diff --git a/spip2md/spipobjects.py b/spip2md/spipobjects.py index 917ccc6..b7a56a9 100644 --- a/spip2md/spipobjects.py +++ b/spip2md/spipobjects.py @@ -26,9 +26,12 @@ from spip2md.regexmap import ( ISO_UTF, MULTILANG_BLOCK, MULTILANGS, + SPECIAL_OUTPUT, SPIP_MARKDOWN, UNKNOWN_ISO, + WARNING_OUTPUT, ) +from spip2md.style import BLUE, BOLD, GREEN, WARNING_STYLE, YELLOW, esc class SpipWritable: @@ -38,6 +41,7 @@ class SpipWritable: titre: str descriptif: str profondeur: int + style: tuple[int, ...] # Returns the first detected language (& instantiate a new object for the second) # (currently don’t instantiate, just warns) @@ -82,6 +86,19 @@ class SpipWritable: f"Subclasses need to implement filename(), date: {date}" ) + # Print one or more string(s) in which special elements are stylized + def style_print(self, string: str, indent: bool = True, end: str = "\n") -> str: + stylized: str = string + for o in SPECIAL_OUTPUT: + stylized = o.sub(esc(*self.style) + r"\1" + esc(), stylized) + for w in WARNING_OUTPUT: + stylized = w.sub(esc(*WARNING_STYLE) + r"\1" + esc(), stylized) + if indent: + stylized = " " * self.profondeur + stylized + print(stylized, end=end) + # Return the stylized string + return stylized + def begin_message(self, index: int, limit: int, step: int = 100) -> list[str]: output: list[str] = [] # Output the remaining number of objects to export every step object @@ -91,12 +108,16 @@ class SpipWritable: output[-1] += f" level {self.profondeur}" s: str = "s" if limit - index > 1 else "" output[-1] += f" {type(self).__name__}{s}" + # Print the output as the program goes + self.style_print(output[-1]) # Output the counter & title of the object being exported output.append(f"{index + 1}. ") if len(self.titre) > 0: - output[-1] += self.titre + output[-1] += self.titre.strip(" ") else: output[-1] += "MISSING NAME" + # Print the output as the program goes + self.style_print(output[-1], end="") return output # Write object to output destination @@ -110,10 +131,15 @@ class SpipWritable: output: str = " -> " if message is Exception: output += "ERROR " + # Print the output as the program goes + self.style_print(output + str(message), indent=False) return output + str(message) class Document(SpipWritable, SpipDocuments): + # Documents accent color is blue + style = (BOLD, BLUE) + class Meta: table_name: str = "spip_documents" @@ -277,6 +303,9 @@ class SpipObject(SpipWritable): class Article(SpipObject, SpipArticles): + # Articles accent color is yellow + style = (BOLD, YELLOW) + class Meta: table_name: str = "spip_articles" @@ -332,6 +361,9 @@ class Article(SpipObject, SpipArticles): class Rubrique(SpipObject, SpipRubriques): + # Sections accent color is green + style = (BOLD, GREEN) + class Meta: table_name: str = "spip_rubriques" @@ -373,6 +405,7 @@ class Rubrique(SpipObject, SpipRubriques): output: list[str] = [] total = len(objects) for i, obj in enumerate(objects): + obj.profondeur = self.profondeur + 1 for m in obj.begin_message(i, total): output.append(m) try: @@ -385,7 +418,7 @@ class Rubrique(SpipObject, SpipRubriques): output.append(write_loop(documents)) # Get all child section of self - child_sections = ( + child_sections: ModelSelect = ( Rubrique.select() .where(Rubrique.id_parent == self.id_rubrique) .order_by(Rubrique.date.desc()) @@ -410,18 +443,20 @@ class RootRubrique(Rubrique): def write_tree( self, parent_dir: str, sections_limit: int = 0, articles_limit: int = 0 - ) -> list[str | list[Any]]: + ) -> list[str | list]: # Define dictionary output to diplay - output: list[str | list[Any]] = [] - # Starting message - output.append( + output: list[str | list] = [] + # Print starting message + print( f"""\ -Begin exporting `{CFG.db}@{CFG.db_host}` SPIP database to plain Markdown+YAML -files into the directory `{parent_dir}`, as database user `{CFG.db_user}` +Begin exporting {esc(BOLD)}{CFG.db}@{CFG.db_host}{esc()} SPIP database to plain \ +Markdown+YAML files, +into the directory {esc(BOLD)}{parent_dir}{esc()}, \ +as database user {esc(BOLD)}{CFG.db_user}{esc(BOLD)} """ ) # Get all child section of self - child_sections = ( + child_sections: ModelSelect = ( Rubrique.select() .where(Rubrique.id_parent == self.id_rubrique) .order_by(Rubrique.date.desc()) @@ -430,4 +465,5 @@ files into the directory `{parent_dir}`, as database user `{CFG.db_user}` # Do the same for subsections (write their entire subtree) for i, s in enumerate(child_sections): output.append(s.write_tree(parent_dir, i, nb)) + print() # Break line for level 1 return output diff --git a/spip2md/style.py b/spip2md/style.py new file mode 100644 index 0000000..3806b02 --- /dev/null +++ b/spip2md/style.py @@ -0,0 +1,27 @@ +# Define styles for terminal printing +BOLD = 1 # Bold +ITALIC = 3 # Italic +UNDER = 4 # Underline +# Define colors +RED = 91 # Red +GREEN = 92 # Green +YELLOW = 93 # Yellow +BLUE = 94 # Blue +C0 = 95 # Color +C1 = 96 # Color +C2 = 96 # Color +# Style used for warnings +WARNING_STYLE = (BOLD, RED) + + +# Terminal escape sequence +def esc(*args: int) -> str: + if len(args) == 0: + params: str = "0;" # Defaults to reset + else: + params: str = "" + # Build a string from args, that will be stripped from its trailing ; + for a in args: + params += str(a) + ";" + # Base terminal escape sequence that needs to be closed by "m" + return "\033[" + params[:-1] + "m"