def define_env(env): "Hook function" env.variables['compteur_exo'] = 0 @env.macro def exercice(var = True, prem = None): """ Crée des numérotations d'exercices automatiques : indiquer exercice(..., 0) pour le premier exercice d'une page puis exercice(....) pour les suivants (numéroation auto) var == True, exercice en dehors d'une superfence. var == False, exercice dans une superfence """ if prem is not None : env.variables['compteur_exo'] = prem env.variables['compteur_exo'] += 1 root = f"Exercice { env.variables['compteur_exo']}" return f"""exo \"{root}\"""" if var else '\"'+root+'\"' @env.macro def cours(): """ raccourci et formatage auto balise cours """ return f'done "Cours"' @env.macro def ext(): return f'ext "Pour aller plus loin"' env.variables['term_counter'] = 0 env.variables['IDE_counter'] = 0 INFTY_SYMBOL = '\u221e' from urllib.parse import unquote @env.macro def terminal() -> str: """ Purpose : Create a Python Terminal. Methods : Two layers to avoid focusing on the Terminal. 1) Fake Terminal using CSS 2) A click hides the fake terminal and triggers the actual Terminal. """ tc = env.variables['term_counter'] env.variables['term_counter'] += 1 return f"""
""" def read_ext_file(nom_script : str, path : str, filetype : str = 'py') -> str: """ Purpose : Read a Python file that is uploaded on the server. Methods : The content of the file is hidden in the webpage. Replacing \n by a string makes it possible to integrate the content in mkdocs admonitions. """ short_path = f"""docs/""" try: if path == "": # print(nom_script, f"""{short_path}/scripts/{nom_script}.{filetype}""") f = open(f"""{short_path}/scripts/{nom_script}.{filetype}""") else: # print('relp', f"""{short_path}/{path}/{nom_script}.{filetype}""") # print(nom_script, f"""{short_path}/{path}/{nom_script}.{filetype}""") f = open(f"""{short_path}/{path}/{nom_script}.{filetype}""") # f = open(f"""{short_path}/scripts/{nom_script}.{filetype}""") content = ''.join(f.readlines()) f.close() content = content + "\n" # Hack to integrate code lines in admonitions in mkdocs # change backslash_newline by backslash-newline return content.replace('\n','bksl-nl').replace('_','py-und').replace('*','py-str') except : return def generate_content(nom_script : str, path : str, filetype : str = 'py') -> str: """ Purpose : Return content and current number IDE {tc}. """ tc = env.variables['IDE_counter'] env.variables['IDE_counter'] += 1 content = read_ext_file(nom_script, path, filetype) if content is not None : return content, tc else : return "", tc def create_upload_button(tc : str) -> str: """ Purpose : Create upload button for a IDE number {tc}. Methods : Use an HTML input to upload a file from user. The user clicks on the button to fire a JS event that triggers the hidden input. """ path_img = env.variables.page.abs_url.split('/')[1] return f"""\ """ def create_unittest_button(tc: str, nom_script: str, path : str, mode: str, MAX : int = 5) -> str: """ Purpose : Generate the button for IDE {tc} to perform the unit tests if a valid test_script.py is present. Methods : Hide the content in a div that is called in the Javascript """ stripped_nom_script = nom_script.split('/')[-1] relative_path = '/'.join(nom_script.split('/')[:-1]) nom_script = f"{relative_path}/{stripped_nom_script}_test" content = read_ext_file(nom_script, path) if content is not None: path_img = env.variables.page.abs_url.split('/')[1] return f"""{content}\ \ {MAX}/{MAX}\ """ else: return '' def blank_space(s=0.3) -> str: """ Purpose : Return 5em blank spaces. Use to spread the buttons evenly """ # return f""" """ return f"""""" def get_max_from_file(content : str) -> tuple:#[str, int]: # compatibilité Python antérieur 3.8 split_content = content.split('bksl-nl') max_var = split_content[0] if max_var[:4] != "#MAX": MAX = 5 else: value = max_var.split('=')[1].strip() MAX = int(value) if value not in ['+', 1000] else INFTY_SYMBOL i = 1 while split_content[i] == '': i += 1 content = 'bksl-nl'.join(split_content[i:]) return content, MAX def test_style(nom_script : str, element : str) -> bool: guillemets = ["'", '"'] ide_style = ["", "v"] styles = [f"""IDE{istyle}({i}{nom_script}{i}""" for i in guillemets for istyle in ide_style] return any([style for style in styles if style in element]) def convert_url_to_utf8(nom : str) -> str: return unquote(nom, encoding='utf-8') @env.macro def IDEv(nom_script : str = '', MAX : int = 5, SANS : str = "") -> str: """ Purpose : Easy macro to generate vertical IDE in Markdown mkdocs. Methods : Fire the IDE function with 'v' mode. """ return IDE(nom_script, mode = 'v', MAX = MAX, SANS = SANS) @env.macro def IDE(nom_script : str = '', mode : str = 'h', MAX : int = 5, SANS : str = "") -> str: """ Purpose : Create an IDE (Editor+Terminal) on a Mkdocs document. {nom_script}.py is loaded on the editor if present. Methods : Two modes are available : vertical or horizontal. Buttons are added through functional calls. Last span hides the code content of the IDE if loaded. """ path_img = convert_url_to_utf8(env.variables.page.abs_url).split('/')[1] path_file = '/'.join(filter(lambda folder: folder != "", convert_url_to_utf8(env.variables.page.abs_url).split('/')[2:-2])) content, tc = generate_content(nom_script, path_file) try: f = open(f"docs/{path_file}/clef.txt", "r", encoding="utf8") clef = f.read() except: clef = "" # base case -> no clef.txt file content, max_from_file = get_max_from_file(content) MAX = max_from_file if MAX == 5 else MAX MAX = MAX if MAX not in ['+', 1000] else INFTY_SYMBOL corr_content, tc = generate_content(f"""{'/'.join(nom_script.split('/')[:-1])}/{nom_script.split('/')[-1]}_corr""", path_file) div_edit = f'
' if mode == 'v': div_edit += f'
' else: div_edit += f'
' div_edit += f"""""" div_edit += create_unittest_button(tc, nom_script, path_file, mode, MAX) div_edit += f"""{blank_space(1)}{blank_space()}""" div_edit += create_upload_button(tc) div_edit += f"""{blank_space(1)}{blank_space()}""" div_edit += f"""""" div_edit += '
' div_edit += f"""{content}""" div_edit += f"""{corr_content}""" elt_insertion = [elt for elt in env.page.markdown.split("\n") if test_style(nom_script, elt)] elt_insertion = elt_insertion[0] if len(elt_insertion) >=1 else "" indent = " "*(len(elt_insertion) - len(elt_insertion.lstrip())) if nom_script == '' : indent = " " # to avoid conflict with empty IDEs if indent == "": div_edit += f''' {indent}--8<--- "docs/xtra/start_REM.md" ''' div_edit += f''' {indent}--8<--- "docs/{path_file if path_file != "" else 'scripts'}/{nom_script}_REM.md"''' if clef == "" else f"" if indent == "": div_edit += f''' {indent}--8<--- "docs/xtra/end_REM.md" ''' return div_edit