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

"""Flask-based GUI editor for scitex-writer projects.

Provides a browser-based interface for editing LaTeX manuscripts
with PDF preview, file tree, and compilation controls.
"""

import logging
import socket
import webbrowser
from pathlib import Path
from threading import Timer

from flask import Flask

logger = logging.getLogger(__name__)


def _find_available_port(host: str, start_port: int) -> int:
    """Find an available port starting from start_port."""
    port = start_port
    for _ in range(100):
        try:
            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
                s.bind((host, port))
                return port
        except OSError:
            port += 1
    return start_port


class WriterEditor:
    """Browser-based LaTeX manuscript editor using Flask.

    Features:
    - File tree sidebar with project structure
    - LaTeX editor with syntax highlighting (CodeMirror)
    - PDF preview panel (pdf.js)
    - One-click compilation (manuscript/supplementary/revision)
    - Dark/light theme toggle
    - Compilation log viewer
    """

    def __init__(
        self,
        project_dir: Path,
        port: int = 5050,
        host: str = "127.0.0.1",
        desktop: bool = False,
    ):
        self.project_dir = Path(project_dir).resolve()
        self.port = port
        self.host = host
        self.desktop = desktop
        self.dark_mode = False

        # Compilation state
        self._compiling = False
        self._compile_result = None
        self._compile_log = ""

        self.app = self._create_app()

    def _create_app(self) -> Flask:
        """Create and configure the Flask application."""
        app = Flask(__name__)
        app.config["MAX_CONTENT_LENGTH"] = 16 * 1024 * 1024  # 16MB max

        from ._routes_bib import register_bib_routes
        from ._routes_claim import register_claim_routes
        from ._routes_compile import register_compile_routes
        from ._routes_core import register_core_routes
        from ._routes_files import register_file_routes

        register_core_routes(app, self)
        register_file_routes(app, self)
        register_compile_routes(app, self)
        register_bib_routes(app, self)
        register_claim_routes(app, self)

        return app

    def run(self, open_browser: bool = True) -> None:
        """Start the Flask server."""
        self.port = _find_available_port(self.host, self.port)
        url = f"http://{self.host}:{self.port}"

        if open_browser and not self.desktop:
            Timer(1.0, webbrowser.open, args=[url]).start()

        print(f"SciTeX Writer GUI: {url}")
        print(f"Project: {self.project_dir}")
        print("Press Ctrl+C to stop")

        if self.desktop:
            try:
                import webview

                webview.create_window(
                    "SciTeX Writer",
                    url,
                    width=1400,
                    height=900,
                )
                Timer(
                    0.5,
                    lambda: self.app.run(
                        host=self.host, port=self.port, debug=False, use_reloader=False
                    ),
                ).start()
                webview.start()
            except ImportError:
                print("pywebview not installed. Falling back to browser mode.")
                self.app.run(
                    host=self.host, port=self.port, debug=False, use_reloader=False
                )
        else:
            self.app.run(
                host=self.host, port=self.port, debug=False, use_reloader=False
            )


# EOF