Loading...
No commits yet
Not committed History
Blame
_watch.py • 2.5 KB
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# File: src/scitex_writer/_utils/_watch.py

"""
Watch mode for auto-recompilation.

Monitors file changes and triggers automatic recompilation.
"""

from __future__ import annotations

import subprocess
from logging import getLogger
from pathlib import Path
from typing import Callable, Optional

logger = getLogger(__name__)


def watch_manuscript(
    project_dir: Path,
    interval: int = 2,
    on_compile: Optional[Callable] = None,
    timeout: Optional[int] = None,
) -> None:
    """
    Watch and auto-recompile manuscript on file changes.

    Args:
        project_dir: Path to writer project directory
        interval: Check interval in seconds
        on_compile: Callback function called after each compilation
        timeout: Optional timeout in seconds (None = infinite)

    Examples:
        >>> from pathlib import Path
        >>> def on_change():
        ...     print("Recompiled!")
        >>> watch_manuscript(Path("/path/to/project"), on_compile=on_change)
    """
    # Get compile script from project directory
    compile_script = project_dir / "compile"

    if not compile_script.exists():
        logger.error(f"compile script not found: {compile_script}")
        return

    # Build watch command
    cmd = [str(compile_script), "-m", "-w"]

    logger.info(f"Starting watch mode for {project_dir}")
    logger.info("Press Ctrl+C to stop")

    process = None
    try:
        # Run watch script
        process = subprocess.Popen(
            cmd,
            cwd=project_dir,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            text=True,
            bufsize=1,  # Line-buffered
        )

        # Stream output
        for line in iter(process.stdout.readline, ""):
            if line:
                print(line.rstrip())

                # Call callback on compilation events
                if on_compile and "Compilation" in line:
                    try:
                        on_compile()
                    except Exception as e:
                        logger.error(f"Callback error: {e}")

        process.wait(timeout=timeout)

    except KeyboardInterrupt:
        logger.info("\nWatch mode stopped by user")
        if process:
            process.terminate()
            try:
                process.wait(timeout=5)
            except subprocess.TimeoutExpired:
                process.kill()

    except Exception as e:
        logger.error(f"Watch mode error: {e}")
        if process:
            process.terminate()


__all__ = ["watch_manuscript"]

# EOF