nice visual improvments
This commit is contained in:
101
PyPost.py
101
PyPost.py
@@ -8,6 +8,7 @@ from jinja2 import Environment, FileSystemLoader
|
||||
import base64
|
||||
import random
|
||||
import time
|
||||
import yaml
|
||||
|
||||
import marko
|
||||
from marko.ext.gfm import GFM
|
||||
@@ -19,7 +20,7 @@ from htmlhandler import htmlhandler as Handler
|
||||
from lua import plugin_manager
|
||||
|
||||
plugin_manager = plugin_manager.PluginManager()
|
||||
plugin_manager.load_all() # load plugins
|
||||
plugin_manager.load_all() # load plugins
|
||||
|
||||
# Use absolute paths
|
||||
ROOT = Path(os.path.abspath("."))
|
||||
@@ -34,7 +35,7 @@ RUST_PARSER_PATH = ROOT / "fastmd" / "target" / "release" / f"fastmd{exe_ext}"
|
||||
if not RUST_PARSER_PATH.exists():
|
||||
RUST_PARSER_PATH = ROOT / "fastmd" / "target" / "debug" / f"fastmd{exe_ext}"
|
||||
|
||||
# Create Python Markdown parser with table support (fallback for small files)
|
||||
# Python Markdown parser with table support
|
||||
markdown_parser = marko.Markdown(extensions=[GFM])
|
||||
|
||||
# Threshold for switching to Rust parser (number of lines)
|
||||
@@ -45,8 +46,22 @@ Logger = Logger()
|
||||
# Global obfuscate flag, default True
|
||||
obfuscate = True
|
||||
|
||||
def split_yaml_front_matter(md_path: Path) -> tuple[str, str]:
|
||||
"""Return (yaml_text, markdown_text). YAML is '' if none exists."""
|
||||
try:
|
||||
text = md_path.read_text(encoding="utf-8")
|
||||
except Exception as e:
|
||||
Logger.log_error(f"Could not read {md_path}: {e}")
|
||||
return '', ''
|
||||
if text.startswith("---"):
|
||||
parts = text.split("---", 2)
|
||||
if len(parts) >= 3:
|
||||
yaml_text = parts[1].strip()
|
||||
markdown_text = parts[2].lstrip("\n")
|
||||
return yaml_text, markdown_text
|
||||
return '', text
|
||||
|
||||
def count_lines_in_file(file_path: Path) -> int:
|
||||
"""Count the number of lines in a file."""
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
return sum(1 for _ in f)
|
||||
@@ -55,24 +70,18 @@ def count_lines_in_file(file_path: Path) -> int:
|
||||
return 0
|
||||
|
||||
def should_use_rust_parser(md_path: Path) -> bool:
|
||||
"""Determine if we should use the Rust parser based on file size."""
|
||||
if not RUST_PARSER_PATH.exists():
|
||||
return False
|
||||
|
||||
line_count = count_lines_in_file(md_path)
|
||||
use_rust = line_count > RUST_PARSER_THRESHOLD
|
||||
|
||||
if use_rust:
|
||||
Logger.log_rust_usage(f"Using Rust parser for {md_path} ({line_count} lines)")
|
||||
else:
|
||||
Logger.log_debug(f"Using Python parser for {md_path} ({line_count} lines)")
|
||||
|
||||
return use_rust
|
||||
|
||||
def parse_markdown_with_rust(md_path: Path) -> str:
|
||||
"""Parse markdown using the Rust parser."""
|
||||
try:
|
||||
# Run the Rust parser
|
||||
result = subprocess.run(
|
||||
[str(RUST_PARSER_PATH), str(md_path)],
|
||||
capture_output=True,
|
||||
@@ -90,31 +99,27 @@ def parse_markdown_with_rust(md_path: Path) -> str:
|
||||
raise
|
||||
|
||||
def render_markdown(md_path: Path):
|
||||
"""Render a single markdown file to an obfuscated HTML file."""
|
||||
try:
|
||||
text = md_path.read_text(encoding="utf-8")
|
||||
except Exception as e:
|
||||
Logger.log_error(f"Could not read {md_path}: {e}")
|
||||
return
|
||||
"""Render a single markdown file to HTML, stripping YAML front matter."""
|
||||
yaml_text, markdown_text = split_yaml_front_matter(md_path)
|
||||
|
||||
# Decide which parser to use based on file size
|
||||
# Choose parser
|
||||
if should_use_rust_parser(md_path):
|
||||
try:
|
||||
html_body = parse_markdown_with_rust(md_path)
|
||||
except Exception as e:
|
||||
Logger.log_warning(f"Rust parser failed for {md_path}, falling back to Python parser: {e}")
|
||||
html_body = markdown_parser.convert(text)
|
||||
html_body = markdown_parser.convert(markdown_text)
|
||||
else:
|
||||
html_body = markdown_parser.convert(text)
|
||||
html_body = markdown_parser.convert(markdown_text)
|
||||
|
||||
# Extract title from filename or first H1
|
||||
title = md_path.stem
|
||||
for line in text.splitlines():
|
||||
for line in markdown_text.splitlines():
|
||||
if line.startswith("# "):
|
||||
title = line[2:].strip()
|
||||
break
|
||||
|
||||
# Call pre_template hook properly
|
||||
|
||||
# Plugin pre_template hook
|
||||
Logger.log_debug(f"Calling pre_template hook for {md_path}")
|
||||
modified = plugin_manager.run_hook("pre_template", str(md_path), html_body)
|
||||
if modified is not None:
|
||||
@@ -123,13 +128,11 @@ def render_markdown(md_path: Path):
|
||||
else:
|
||||
Logger.log_debug("pre_template hook returned None")
|
||||
|
||||
# Create clean HTML structure
|
||||
# Pick two different hashes from hash_list
|
||||
# Jinja template
|
||||
env = Environment(loader=FileSystemLoader("html/base"))
|
||||
template = env.get_template("template.html")
|
||||
hash1, hash2 = random.sample(hash_list, 2)
|
||||
|
||||
# Load these variable for Jinja to use.
|
||||
clean_jinja_html = template.render(
|
||||
title=title,
|
||||
html_body=html_body,
|
||||
@@ -139,23 +142,36 @@ def render_markdown(md_path: Path):
|
||||
timestamp=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
|
||||
)
|
||||
|
||||
# Plugin post_render hook
|
||||
post_mod = plugin_manager.run_hook("post_render", str(md_path), clean_jinja_html)
|
||||
if post_mod is not None:
|
||||
clean_jinja_html = post_mod
|
||||
|
||||
# Ensure html directory exists
|
||||
# Write output
|
||||
HTML_DIR.mkdir(exist_ok=True)
|
||||
|
||||
# Maintain relative directory structure in html/
|
||||
relative_path = md_path.relative_to(MARKDOWN_DIR)
|
||||
out_path = HTML_DIR / relative_path.with_suffix(".html")
|
||||
|
||||
# Create parent directories if needed
|
||||
out_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
out_path.write_text(clean_jinja_html, encoding="utf-8")
|
||||
Logger.log_debug(f"Rendered: {md_path} -> {out_path}")
|
||||
|
||||
def extract_summary(md_path: Path) -> tuple[str, str] | None:
|
||||
yaml_text, _ = split_yaml_front_matter(md_path)
|
||||
if not yaml_text:
|
||||
Logger.log_debug(f"No YAML front matter in {md_path}")
|
||||
return None
|
||||
try:
|
||||
data = yaml.safe_load(yaml_text)
|
||||
summary = data.get("summary")
|
||||
if summary:
|
||||
html_name = md_path.with_suffix(".html").name
|
||||
return html_name, summary
|
||||
else:
|
||||
Logger.log_debug(f"No 'summary' key in YAML of {md_path}")
|
||||
except Exception as e:
|
||||
Logger.log_warning(f"Failed to parse YAML summary in {md_path}: {e}")
|
||||
return None
|
||||
|
||||
def remove_html(md_path: Path):
|
||||
relative_path = md_path.relative_to(MARKDOWN_DIR)
|
||||
out_path = HTML_DIR / relative_path.with_suffix(".html")
|
||||
@@ -170,20 +186,15 @@ def initial_scan(markdown_dir: Path):
|
||||
|
||||
def build_rust_parser() -> bool:
|
||||
fastmd_dir = ROOT / "fastmd"
|
||||
|
||||
if not fastmd_dir.exists():
|
||||
Logger.log_error(f"fastmd directory not found at {fastmd_dir}")
|
||||
return False
|
||||
|
||||
cargo_toml = fastmd_dir / "Cargo.toml"
|
||||
if not cargo_toml.exists():
|
||||
Logger.log_error(f"Cargo.toml not found at {cargo_toml}")
|
||||
return False
|
||||
|
||||
Logger.log_info("Attempting to build Rust parser with 'cargo build --release'...")
|
||||
|
||||
try:
|
||||
# Run cargo build --release in the fastmd directory
|
||||
result = subprocess.run(
|
||||
["cargo", "build", "--release"],
|
||||
cwd=str(fastmd_dir),
|
||||
@@ -191,11 +202,9 @@ def build_rust_parser() -> bool:
|
||||
text=True,
|
||||
check=True
|
||||
)
|
||||
|
||||
Logger.log_info("Rust parser built successfully!")
|
||||
Logger.log_debug(f"Build output: {result.stdout}")
|
||||
return True
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
Logger.log_error(f"Failed to build Rust parser: {e}")
|
||||
Logger.log_error(f"Build stderr: {e.stderr}")
|
||||
@@ -208,7 +217,7 @@ def build_rust_parser() -> bool:
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Check for markdown directory
|
||||
# Handle alternative markdown folder
|
||||
if not MARKDOWN_DIR.exists():
|
||||
alt_root = ROOT / "PyPost"
|
||||
if alt_root.exists() and alt_root.is_dir():
|
||||
@@ -216,7 +225,6 @@ if __name__ == "__main__":
|
||||
ROOT = alt_root
|
||||
MARKDOWN_DIR = ROOT / "markdown"
|
||||
HTML_DIR = ROOT / "html"
|
||||
# Update Rust parser path for new root
|
||||
RUST_PARSER_PATH = ROOT / "fastmd" / "target" / "release" / f"fastmd{exe_ext}"
|
||||
if not RUST_PARSER_PATH.exists():
|
||||
RUST_PARSER_PATH = ROOT / "fastmd" / "target" / "debug" / f"fastmd{exe_ext}"
|
||||
@@ -224,18 +232,14 @@ if __name__ == "__main__":
|
||||
Logger.log_error(f"Markdown directory not found: {MARKDOWN_DIR}")
|
||||
Logger.log_warning("Please create a 'markdown' directory or use a 'PyPost' directory with one inside it.")
|
||||
sys.exit(1)
|
||||
|
||||
# Check if Rust parser exists, if not try to build it
|
||||
|
||||
# Build Rust parser if missing
|
||||
if not RUST_PARSER_PATH.exists():
|
||||
Logger.log_warning(f"Rust parser not found at {RUST_PARSER_PATH}")
|
||||
|
||||
# Try to build the Rust parser
|
||||
if build_rust_parser():
|
||||
# Update path after successful build
|
||||
RUST_PARSER_PATH = ROOT / "fastmd" / "target" / "release" / f"fastmd{exe_ext}"
|
||||
if not RUST_PARSER_PATH.exists():
|
||||
RUST_PARSER_PATH = ROOT / "fastmd" / "target" / "debug" / f"fastmd{exe_ext}"
|
||||
|
||||
if RUST_PARSER_PATH.exists():
|
||||
Logger.log_info(f"Rust parser built and found at: {RUST_PARSER_PATH}")
|
||||
else:
|
||||
@@ -246,13 +250,12 @@ if __name__ == "__main__":
|
||||
Logger.log_warning("Will use Python parser for all files")
|
||||
else:
|
||||
Logger.log_info(f"Rust parser found at: {RUST_PARSER_PATH}")
|
||||
|
||||
# Log parser strategy
|
||||
|
||||
if RUST_PARSER_PATH.exists():
|
||||
Logger.log_info(f"Will use Rust parser for files with more than {RUST_PARSER_THRESHOLD} lines")
|
||||
else:
|
||||
Logger.log_warning("Using Python parser for all files")
|
||||
|
||||
|
||||
initial_scan(MARKDOWN_DIR)
|
||||
event_handler = Handler()
|
||||
observer = Observer()
|
||||
@@ -264,4 +267,4 @@ if __name__ == "__main__":
|
||||
time.sleep(1)
|
||||
except KeyboardInterrupt:
|
||||
observer.stop()
|
||||
observer.join()
|
||||
observer.join()
|
||||
|
||||
Reference in New Issue
Block a user