diff --git a/src/atsphinx/typst/builders.py b/src/atsphinx/typst/builders.py index 53ff2ed..27d4748 100644 --- a/src/atsphinx/typst/builders.py +++ b/src/atsphinx/typst/builders.py @@ -49,12 +49,19 @@ def get_outdated_docs(self): # noqa: D102 return "all targets" def prepare_writing(self, docnames: set[str]) -> None: # noqa: D102 + """ + Preload themes to copy assets before write_documents. + args: + docnames: set[str] unused parameter + """ # Preload themes to copy assets before write_documents. def _load_theme(name: str) -> theming.Theme | None: if name in self._themes: return - theme = theming.load_theme(name) + theme = theming.load_theme( + name, typst_themes_path=self.config.typst_themes_path + ) theme.init(self) self._themes[name] = theme parent = theme.get_parent_theme() diff --git a/src/atsphinx/typst/config.py b/src/atsphinx/typst/config.py index 560f444..3ce371e 100644 --- a/src/atsphinx/typst/config.py +++ b/src/atsphinx/typst/config.py @@ -56,25 +56,40 @@ def compute_configurations(app: Sphinx, config: Config): "filename": f"document-{config.language}", "title": f"{config.project} Documentation [{config.language.upper()}]", "author": config.author, - "theme": "manual", + "theme": config.theme, } ) for idx, user_value in enumerate(document_settings): document_settings[idx] = DEFAULT_DOCUMENT_SETTINGS | user_value config.typst_documents = document_settings - # 2. Cast string path to Path object. + # 2. Cast string path to Path object for static_paths typst_static_path = [] for p in config.typst_static_path: if isinstance(p, Path): - typst_static_path.append(p) + typst_static_path.append(p if p.is_absolute() else app.confdir / p) continue typst_static_path.append(app.confdir / p) config.typst_static_path = typst_static_path + # 3. Cast string path to Path object for themes_paths + typst_themes_path = [] + for p in config.typst_themes_path: + if isinstance(p, Path): + typst_themes_path.append(p if p.is_absolute() else app.confdir / p) + else: + typst_themes_path.append(app.confdir / p) + config.typst_themes_path = typst_themes_path + + +def setup(app: Sphinx): + """Register configuration values and connect event handlers. -def setup(app: Sphinx): # noqa: D103 + Args: + app: Sphinx application instance + """ app.add_config_value("typst_documents", [], "env", list[dict]) app.add_config_value("typst_static_path", [], "env", [list[str | Path]]) + app.add_config_value("typst_themes_path", [], "env", [list[str | Path]]) app.add_config_value("typst_font_paths", [], "env", [list[str | Path]]) app.connect("config-inited", compute_configurations) diff --git a/src/atsphinx/typst/theming.py b/src/atsphinx/typst/theming.py index fc35963..1b92e4e 100644 --- a/src/atsphinx/typst/theming.py +++ b/src/atsphinx/typst/theming.py @@ -152,7 +152,7 @@ def _verify_theme_path(theme_dir: Path) -> bool: ) -def load_theme(name: str) -> Theme: +def load_theme(name: str, typst_themes_path: list[Path] = []) -> Theme: """Find theme directory and load as theme object. If it is not found, raise error. @@ -164,9 +164,16 @@ def load_theme(name: str) -> Theme: def _find_theme_path(name: str) -> Path: """Search theme path in order to rules. + Searches custom theme directories first, then built-in themes. When it does not found, it raises ThemeError. """ + # Search from custom theme directories first + for custom_dir in typst_themes_path: + theme_dir = custom_dir / name + if _verify_theme_path(theme_dir): + return theme_dir + # Search from built-in themes theme_dir = _BASE_THEMES_DIR / name if _verify_theme_path(theme_dir):