182 lines
6.1 KiB
Python
182 lines
6.1 KiB
Python
import re
|
|
from pathlib import Path
|
|
|
|
from platform_utils import validate_windows_labels
|
|
|
|
def natural_key(text):
|
|
return [int(c) if c.isdigit() else c.lower() for c in re.split(r'(\d+)', str(text))]
|
|
|
|
def read_all_labels(base_dir):
|
|
labels = list(filter(None, (Path(base_dir) / "labels").read_text().splitlines()))
|
|
validate_windows_labels(labels)
|
|
return labels
|
|
|
|
def enonce_total(base_dir):
|
|
text_dir = Path(base_dir) / 'Text'
|
|
if not text_dir.is_dir():
|
|
return ""
|
|
|
|
files = [f for f in text_dir.iterdir() if f.is_file() and f.suffix not in [".pdf", ".tex"]]
|
|
files.sort(key=lambda f: natural_key(f.name))
|
|
|
|
output = []
|
|
for filepath in files:
|
|
content = filepath.read_text(encoding='utf-8')
|
|
output.append(f"{filepath.name}\n{content}\n\n\n")
|
|
|
|
return "".join(output)
|
|
|
|
import os
|
|
import shlex
|
|
|
|
from platform_utils import open_path
|
|
|
|
def edit_file_and_enter(file):
|
|
editor = os.environ.get("EDITOR")
|
|
try:
|
|
if editor:
|
|
subprocess.run(shlex.split(editor, posix=os.name != "nt") + [str(file)])
|
|
else:
|
|
open_path(file)
|
|
input("Press ENTER here once you have saved and closed the text file...")
|
|
except Exception as e:
|
|
print(f"Error running editor: {e}")
|
|
|
|
|
|
def pdf_image_of_enonce(root_dir, label):
|
|
pdf_path = os.path.join(root_dir, "Text2", f"{label}.pdf")
|
|
if os.path.exists(pdf_path):
|
|
return pdf_path
|
|
|
|
def pdf_image_of_solution(root_dir, label):
|
|
pdf_path = os.path.join(root_dir, "Sol2", f"{label}.pdf")
|
|
if os.path.exists(pdf_path):
|
|
return pdf_path
|
|
|
|
def pdf_images_of_contexts(root_dir, label, all_labels):
|
|
text2_dir = os.path.join(root_dir, "Text2")
|
|
if not os.path.isdir(text2_dir):
|
|
return []
|
|
|
|
# Map safe labels (with '/' replaced by '_') to their chronological index
|
|
safe_to_idx = {l.replace("/", "_"): i for i, l in enumerate(all_labels)}
|
|
|
|
safe_target = label.replace("/", "_")
|
|
target_idx = safe_to_idx.get(safe_target, -1)
|
|
|
|
if target_idx == -1:
|
|
return []
|
|
|
|
pertinent_contexts = []
|
|
|
|
for filename in os.listdir(text2_dir):
|
|
if filename.startswith("CTXT ") and filename.endswith(".pdf"):
|
|
# Extract "first_label -> last_label" from "CTXT first_label -> last_label.pdf"
|
|
core = filename[5:-4]
|
|
parts = core.split(" -> ")
|
|
|
|
if len(parts) == 2:
|
|
first_safe, last_safe = parts
|
|
first_idx = safe_to_idx.get(first_safe, -1)
|
|
last_idx = safe_to_idx.get(last_safe, -1)
|
|
|
|
# Check if the current label falls within the context's validity range
|
|
if first_idx != -1 and last_idx != -1:
|
|
if first_idx <= target_idx <= last_idx:
|
|
pdf_path = os.path.join(text2_dir, filename)
|
|
pertinent_contexts.append((first_idx, pdf_path))
|
|
|
|
# Sort by first_idx to ensure contexts are returned in logical reading order
|
|
pertinent_contexts.sort(key=lambda x: x[0])
|
|
return [path for _, path in pertinent_contexts]
|
|
|
|
|
|
def get_exam_file_content(folder_path, mode, label):
|
|
"""
|
|
Retrieves content from the Text or Sol directory for a specific label.
|
|
Checks for exact filename matches or grouped 'prefix[a,b,c]' filenames.
|
|
"""
|
|
target_dir = Path(folder_path) / mode
|
|
if not target_dir.is_dir():
|
|
return None
|
|
|
|
# Sanitize label (consistent with the script's saving logic)
|
|
safe_label = label.replace("/", "_")
|
|
|
|
# 1. Try exact filename match
|
|
direct_file = target_dir / safe_label
|
|
if direct_file.is_file():
|
|
return direct_file.read_text(encoding="utf-8")
|
|
|
|
# 2. Search for grouped files: prefix[suffix1,suffix2,...]
|
|
for file_path in target_dir.iterdir():
|
|
if not file_path.is_file():
|
|
continue
|
|
name = file_path.name
|
|
if "[" in name and name.endswith("]"):
|
|
# Split 'prefix[suffixes]' -> 'prefix', 'suffixes'
|
|
prefix, rest = name.split("[", 1)
|
|
suffixes = rest[:-1].split(",") # Remove trailing ']' and split
|
|
|
|
# Check if any reconstructed label matches
|
|
for s in suffixes:
|
|
if (prefix + s) == safe_label:
|
|
return file_path.read_text(encoding="utf-8")
|
|
|
|
return None
|
|
|
|
def get_label_text_content(folder, label):
|
|
return get_exam_file_content(folder, "Text", label)
|
|
|
|
def get_label_sol_content(folder, label):
|
|
return get_exam_file_content(folder, "Sol", label)
|
|
|
|
def get_label_persp_content(folder, label):
|
|
return get_exam_file_content(folder, "Persp", label)
|
|
|
|
import tempfile
|
|
import shutil
|
|
import subprocess
|
|
|
|
from config import LATEX_AFTER, LATEX_BEFORE
|
|
|
|
|
|
def compile_to_pdf(text, output_pdf_path):
|
|
"""Wraps text in standalone header/footer templates and compiles it to PDF."""
|
|
latex_template = f"{LATEX_BEFORE}{text}{LATEX_AFTER}"
|
|
|
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
tex_filename = 'text.tex'
|
|
pdf_filename = 'text.pdf'
|
|
tex_path = os.path.join(temp_dir, tex_filename)
|
|
|
|
with open(tex_path, 'w', encoding='utf-8') as f:
|
|
f.write(latex_template)
|
|
|
|
# Set TEXINPUTS so pdflatex can find commands.sty if it's in the current dir
|
|
# env = os.environ.copy()
|
|
# current_dir = os.getcwd()
|
|
# env['TEXINPUTS'] = f".:{current_dir}:"
|
|
|
|
try:
|
|
subprocess.run(
|
|
['pdflatex', '-interaction=nonstopmode', tex_filename],
|
|
cwd=temp_dir,
|
|
stdout=subprocess.DEVNULL,
|
|
stderr=subprocess.DEVNULL,
|
|
check=False
|
|
)
|
|
if "minted" in text:
|
|
subprocess.run(
|
|
['pdflatex', '-interaction=nonstopmode', tex_filename],
|
|
cwd=temp_dir,
|
|
stdout=subprocess.DEVNULL,
|
|
stderr=subprocess.DEVNULL,
|
|
check=False)
|
|
|
|
generated_pdf = os.path.join(temp_dir, pdf_filename)
|
|
if os.path.exists(generated_pdf):
|
|
shutil.move(generated_pdf, output_pdf_path)
|
|
except Exception as e:
|
|
print(f"Compilation error for {output_pdf_path}: {e}")
|