Automatically add content from .. include:: directives (#6)

This commit is contained in:
Jared Dillard
2025-05-16 14:33:34 -07:00
committed by GitHub
parent 74393bcd2a
commit 2ca3052a2c
9 changed files with 241 additions and 0 deletions
+98
View File
@@ -100,6 +100,10 @@ class LLMSFullManager:
def combine_sources(self, outdir: str, srcdir: str):
"""Combine all source files into a single file."""
# Store the source directory for resolving include directives
self.srcdir = srcdir
self.outdir = outdir
# Get the correct page order
page_order = self.get_page_order()
@@ -240,6 +244,9 @@ class LLMSFullManager:
def _read_source_file(self, file_path: Path, docname: str) -> tuple:
"""Read and format a single source file.
Handles include directives by replacing them with the content of the included
file.
Returns:
tuple: (content_str, line_count) where line_count is the number of lines
in the file
@@ -248,6 +255,9 @@ class LLMSFullManager:
with open(file_path, "r", encoding="utf-8") as f:
content = f.read()
# Process include directives
content = self._process_includes(content, file_path)
# Count the lines in the content
line_count = content.count("\n") + (0 if content.endswith("\n") else 1)
@@ -261,6 +271,94 @@ class LLMSFullManager:
logger.error(f"sphinx-llm-txt: Error reading source file {file_path}: {e}")
return "", 0
def _process_includes(self, content: str, source_path: Path) -> str:
"""Process include directives in content.
Args:
content: The source content to process
source_path: Path to the source file (to resolve relative paths)
Returns:
Processed content with include directives replaced with included content
"""
import os
import re
# Find all include directives using regex
include_pattern = re.compile(r"^\.\.\s+include::\s+([^\s]+)\s*$", re.MULTILINE)
# Function to replace each include with content
def replace_include(match):
include_path = match.group(1)
# Try multiple possible paths for the include file
possible_paths = []
# If it's an absolute path, use it directly
if os.path.isabs(include_path):
possible_paths.append(Path(include_path))
else:
# Relative to the source file (in _sources directory)
possible_paths.append((source_path.parent / include_path).resolve())
# If we're in _sources directory, try relative to the original source
# directory
if "_sources" in str(source_path):
# Extract the relative path portion from the source path
rel_path = None
try:
# Get the part after _sources/
path_parts = str(source_path).split("_sources/")
if len(path_parts) > 1:
rel_path = path_parts[1]
# Remove .txt extension if present
if rel_path.endswith(".txt"):
rel_path = rel_path[:-4]
except Exception:
pass
# If we have the original source directory from Sphinx
if hasattr(self, "srcdir") and self.srcdir:
# Try in the srcdir root
possible_paths.append(
(Path(self.srcdir) / include_path).resolve()
)
# If we have a relative path, try in the corresponding source
# subdirectory
if rel_path:
rel_dir = os.path.dirname(rel_path)
if rel_dir:
possible_paths.append(
(
Path(self.srcdir) / rel_dir / include_path
).resolve()
)
# Try each possible path
for path_to_try in possible_paths:
try:
if path_to_try.exists():
with open(path_to_try, "r", encoding="utf-8") as f:
included_content = f.read()
return included_content
except Exception as e:
logger.error(
f"sphinx-llms-txt: Error reading include file {path_to_try}:"
f" {e}"
)
continue
# If we get here, we couldn't find the file
paths_tried = ", ".join(str(p) for p in possible_paths)
logger.warning(f"sphinx-llms-txt: Include file not found: {include_path}")
logger.debug(f"sphinx-llms-txt: Tried paths: {paths_tried}")
return f"[Include file not found: {include_path}]"
# Replace all includes with their content
processed_content = include_pattern.sub(replace_include, content)
return processed_content
def _log_summary_info(self, page_order: List[str], total_line_count: int = 0):
"""Log summary information to the logger."""
logger.info("")