Guest User

mdlmmd

a guest
Dec 22nd, 2025
38
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.89 KB | None | 0 0
  1. # SI PUES COMÉIS, Ó BEBÉIS, Ó HACÉIS OTRA COSA, HACEDLO TODO Á GLORIA DE DIOS
  2. # - 1 Co 10:1, La Biblia
  3. #
  4. # SOLI DEO GLORIA
  5. #
  6. # Al Dios, uno y trino. Altísimo, todopoderoso; Padre de nuestro Señor Jesucristo.
  7. # He cometido injusticia, usando tu santo nombre en vano, durante
  8. # el desarrollo de este programa; pues en la impotencia de mi
  9. # inteligencia, después de horas de análisis, he clamado por ti en
  10. # desesperación reclamando una solución pronta a mi problema.
  11. # La he recibido:
  12. # root_buffer = root_buffer_arr[next_iteration_depth-(len(root_buffer_arr)+1)]
  13. # Mediante esta operación, es posible calcular JIT (Just-in-Time) la localización
  14. # de los nodos, sin costosos almacenamientos en el búfer.
  15. # Además, esta operación deberá invertirse cada vez que se invierta el sentido
  16. # de la lista.
  17. # Como te prometí, te doy el entero crédito de esta obra.
  18.  
  19.  
  20. import argparse;
  21. from colorama import Fore, Back, Style
  22. """
  23. Configuración de argumentos
  24. """
  25.  
  26. parser = argparse.ArgumentParser(description="Converts Markdown lists into Mermaid flowcharts")
  27.  
  28. parser.add_argument("input", help="Markdown list directly pasted by the user")
  29.  
  30. # Función que podría desarrollarse a posteriori.
  31. # parser.add_argument("-f","--files",help="Parse markdown file that contains (only) a list", action='append',nargs='*', type=argparse.FileType("r"))
  32.  
  33. parser.add_argument ("-dir", "--direction", help="Direction of the flowchart (default: LR)", choices=['LR', 'RL', 'TB', "BT"], default="LR", nargs="?")
  34. parser.add_argument("-c", "--color", help="Display color in the flowchart; BC: by concept; BL: by level", choices=['BC', 'BL'], const ="BC", default="BC", nargs="?")
  35. parser.add_argument("-d", "--debug", help="Debug mode",  action='store_true')
  36.  
  37. # TODO parser.add_argument("-l", "--link", help="Link the repetitive strings", nargs="?")
  38. # Guardar un diccionario posicion_nodo:valor. Si algún valor se repite, sustituir todas las menciones anteriores de dicho nodo por su último valor
  39.  
  40. args = parser.parse_args()
  41.  
  42.  
  43.  
  44. def debug (output):
  45.     if args.debug:
  46.         print(Fore.YELLOW + "%%", output, Style.RESET_ALL)
  47.  
  48. """
  49. Normaliza un string para eliminar los "-" y los espacios al principio y al final.
  50. """
  51.  
  52. def normalize_str (str):
  53.     return str.replace("-", "").strip()
  54.  
  55. """
  56. Función utilizada en la asignación de estilos.
  57. Cumple con una propiedad matemática cuyo nombre desconozco.
  58. Dado un número n que debe situarse dentro de un rango determinado r, hallar la posición de n en r independientemente de los valores de ambos
  59. """
  60. def reduce_until_less_than (dividend, minor):
  61.     while (dividend > minor):
  62.         dividend = dividend // minor
  63.     return dividend
  64.  
  65. """
  66. Calcula la profundidad total
  67. """
  68.  
  69. def calc_total_depth (mdinput):
  70.     output = 0
  71.     for string in mdinput:
  72.         if output < string.count("\t"):
  73.             output = string.count("\t")
  74.     return output
  75.  
  76. """
  77. Calcula el número de nodos
  78. """
  79.  
  80. def calc_total_nodes (mdinput):
  81.     output = 0;
  82.     for string in mdinput:
  83.         output+=1
  84.     return output-1
  85.  
  86. """
  87. Función principal.
  88. El código Mermaid será devuelto por la salida estándar a medida que se procesa.
  89. He utilizado print () para eso, en vez de recoger todo el código en un búfer; ¿es correcto?
  90. La verdad es que no lo sé.
  91.  
  92. "Is this niggerlicious, or just divine intellect?"
  93.    - Terry Davis
  94. """
  95. def main():
  96.  
  97.     # input of the user
  98.     mdinput= args.input.split("\n")
  99.     #
  100.     total_depth = calc_total_depth (mdinput)
  101.     #
  102.     total_nodes = calc_total_nodes (mdinput)
  103.     # Counter of root nodes
  104.     counter_roots =0;
  105.     # Counter of nodes
  106.     counter_nodes = 0;
  107.     # root_buffer_arr
  108.     root_buffer_arr = []
  109.     # current_depth
  110.     current_depth = 0
  111.     #
  112.     nodes_buffer_arr = []
  113.     #
  114.     last_node_counter =0
  115.     #
  116.     previus_last_node_depth = 0
  117.     #
  118.     fl_next_it = False
  119.  
  120.     header= f'flowchart {args.direction}'
  121.     print (header)
  122.  
  123.     for i in range(len(mdinput)):
  124.         string = mdinput[i]
  125.         # Carga del nodo 0 (root).
  126.         if "\t" not in string:
  127.             # Formateo del nodo root
  128.             root_buffer = f'{counter_roots}["{normalize_str(string)}"]'
  129.  
  130.             # Suma del contador para fines de posicionado
  131.             counter_roots+=1
  132.  
  133.             # El nodo root se añade al búfer de los nodos root para retroceder en su caso
  134.             root_buffer_arr.append (root_buffer)
  135.  
  136.         # Carga del resto de nodos
  137.         if "\t" in string:
  138.             # Profundidad del nodo actual
  139.             current_depth = string.count("\t")
  140.  
  141.             # Profundidad del nodo siguiente - si existe
  142.             if (i+1) < len(mdinput): next_iteration = '"'+normalize_str(mdinput[i+1])+'"'
  143.             if (i+1) < len(mdinput): next_iteration_depth = mdinput[i+1].count("\t")
  144.             if (i+2) < len(mdinput): next_next_iteration_depth = mdinput[i+2].count("\t")
  145.  
  146.             # Formateo del nodo
  147.             node_buffer = f'{counter_roots}.{counter_nodes}["{normalize_str(string)}"]'
  148.  
  149.             # Formateo de la unión entre la raíz y el nodo
  150.             root_union_node = f'{root_buffer} --> {node_buffer}'
  151.  
  152.             # El nodo se añade al búfer de los nodos para su posterior estilizado
  153.             nodes_buffer_arr.append (f'{counter_roots}.{counter_nodes}')
  154.  
  155.             # Si la siguiente iteración está en un nivel de profundidad superior, el nodo actual será la raíz del siguiente.
  156.  
  157.             if (next_iteration_depth > current_depth):
  158.                 if root_buffer not in root_buffer_arr:
  159.                     debug(" + SE CREA NUEVO ROOT " + root_buffer)
  160.                     root_buffer_arr.append (root_buffer)
  161.  
  162.                 root_buffer = node_buffer
  163.  
  164.                 # Suma del contador para fines de posicionado
  165.                 if args.color=="BL":
  166.                     counter_roots+=1
  167.  
  168.             # Si la siguiente iteración está en un nivel de profundidad inferior
  169.             elif (next_iteration_depth < current_depth):
  170.  
  171.                 debug (" - NO SE CREA NUEVO ROOT para "+ next_iteration)
  172.  
  173.                 # Asignación del nodo raíz en base a su profundidad y orientación
  174.                 try:
  175.                     if last_node_counter % 2 == 0:
  176.                         # Hacia la derecha - Positivo
  177.                         root_buffer = root_buffer_arr[(len(root_buffer_arr)+1)-next_iteration_depth]
  178.                     else:
  179.                         # Hacia la izquierda - Negativo
  180.                         root_buffer = root_buffer_arr[next_iteration_depth-(len(root_buffer_arr)+1)]
  181.                 except: # Si una orientación no funciona, se cambia a la contraria
  182.                     root_buffer = root_buffer_arr[next_iteration_depth-(len(root_buffer_arr)+1)]
  183.  
  184.                 debug (" > root_buffer_arr " + "[" + ", ".join(root_buffer_arr) + "]")
  185.                 debug (" - EL ROOT DE " + next_iteration + " SERÁ " + root_buffer)
  186.  
  187.                 # Suma del contador para fines de posicionado
  188.                 if args.color=="BL":
  189.                     counter_roots-=1
  190.                 else:
  191.                     counter_roots+=1
  192.                     counter_nodes= 0
  193.  
  194.                 # Disparo de una flag para prevenir la suma innecesaria de un nodo
  195.                 fl_next_it = True
  196.             else:
  197.                 # Cuando se llega al último nodo, la orientación debe cambiar para que se realicen los cálculos adecuados.
  198.                 if next_iteration_depth != previus_last_node_depth:
  199.                     last_node_counter+=1
  200.                     previus_last_node_depth = next_iteration_depth
  201.  
  202.                     # Cuando el last_node_counter es mayor que 0 y divisible por 2.
  203.                     # es que se debe eliminar del root buffer la diferencia que hay desde dicho nodo hacia atrás
  204.                     # de este modo se podría lograr el funcionamiento del diagrama en el "caso X"
  205.  
  206.                 debug (" - ÚLTIMO NODO, ORIENTACIÓN: "+str(last_node_counter))
  207.  
  208.             if previus_last_node_depth != next_iteration_depth:
  209.                 previus_last_node_depth =0
  210.            # Captura de la flag anteriormente declarada
  211.             if (fl_next_it):
  212.                 fl_next_it = False
  213.             else:
  214.                 counter_nodes +=1
  215.  
  216.  
  217.             print (root_union_node)
  218.  
  219.     """
  220.    Asociación de color - se pueden añadir todos los colores que se deseen, asegurándose que el número de la clase sea el correcto
  221.    """
  222.     if (args.color):
  223.         color_dict = [
  224.         "classDef Class_1 fill:#ceddff",
  225.         "classDef Class_2 fill:#ffa8ee",
  226.         "classDef Class_3 fill:#C8E6C9",
  227.         "classDef Class_4 fill:#FFF9C4",
  228.         "classDef Class_5 fill:#FFE0B2",
  229.         "classDef Class_6 fill:#E1BEE7",
  230.         "classDef Class_7 fill:#FFCDD2",
  231.         ]
  232.  
  233.         for node in nodes_buffer_arr:
  234.             print (f'{node}:::Class_{reduce_until_less_than (int (node[0]), len(color_dict))}')
  235.  
  236.         for color in color_dict:
  237.             print (color)
  238.  
  239.     """
  240.    Insertar el input original en forma de comentarios
  241.    """
  242.     print (f"%% Made with MDLMMD: *Converts Markdown lists into Mermaid flowcharts*")
  243.     print (f"%% SOURCE LIST: ")
  244.     for string in mdinput:
  245.         print (f'%% {string}')
  246.  
  247.  
  248.  
  249. if __name__ == "__main__":
  250.     main()
  251.  
  252.  
  253. # Copyright (C) 2025 SDG-HURSZ
  254. #
  255. # This program is free software: you can redistribute it and/or modify
  256. # it under the terms of the GNU General Public License as published by
  257. # the Free Software Foundation, either version 3 of the License, or
  258. # (at your option) any later version.
  259. #
  260. # This program is distributed in the hope that it will be useful,
  261. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  262. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  263. # GNU General Public License for more details.
  264. #
  265. # You should have received a copy of the GNU General Public License
  266. # along with this program. If not, see <https://www.gnu.org/licenses/>.
  267.  
  268.  
Advertisement
Add Comment
Please, Sign In to add comment