Skip to content

SyncTeX API Reference

Auto-generated API documentation for the synctex module.

synctex

SyncTeX parser for bidirectional search between PDF and source.

Pure Python implementation using only the standard library. Parses .synctex or .synctex.gz files produced by TeX engines with -synctex=1 and provides spatial queries for both directions:

  • Inverse search: PDF position → source file and line number
  • Forward search: Source file and line number → PDF position

Typical usage::

data = parse_synctex("main.synctex.gz", strip_prefix="/workspace/")

# Inverse: click on PDF → find source
result = inverse_search(data, page=1, x=150.0, y=300.0)
# result: {"file": "main.tex", "line": 42}

# Forward: jump from source → find PDF position
result = forward_search(data, file="main.tex", line=42)
# result: {"page": 1, "x": 150.0, "y": 300.0}

Part of zerodep: https://github.com/Oaklight/zerodep Copyright (c) 2026 Peng Ding. MIT License.

HBox dataclass

A horizontal box record from a SyncTeX file.

Represents a line-level element with its source location and bounding box in scaled points.

Source code in synctex/synctex.py
@dataclass
class HBox:
    """A horizontal box record from a SyncTeX file.

    Represents a line-level element with its source location and
    bounding box in scaled points.
    """

    tag: int
    line: int
    x: int  # left edge in scaled points
    y: int  # top edge in scaled points (from page top)
    width: int = 0
    height: int = 0
    depth: int = 0

SyncTeXData dataclass

Parsed SyncTeX data ready for spatial queries.

Attributes:

Name Type Description
inputs dict[int, str]

Mapping from file tag (int) to file path (str).

pages dict[int, list[HBox]]

Mapping from 1-based page number to list of HBox records.

magnification int

TeX magnification factor (typically 1000).

unit int

Coordinate unit in scaled points (typically 1).

x_offset int

Horizontal offset in scaled points.

y_offset int

Vertical offset in scaled points.

Source code in synctex/synctex.py
@dataclass
class SyncTeXData:
    """Parsed SyncTeX data ready for spatial queries.

    Attributes:
        inputs: Mapping from file tag (int) to file path (str).
        pages: Mapping from 1-based page number to list of HBox records.
        magnification: TeX magnification factor (typically 1000).
        unit: Coordinate unit in scaled points (typically 1).
        x_offset: Horizontal offset in scaled points.
        y_offset: Vertical offset in scaled points.
    """

    inputs: dict[int, str] = field(default_factory=dict)
    pages: dict[int, list[HBox]] = field(default_factory=dict)
    magnification: int = 1000
    unit: int = 1
    x_offset: int = 0
    y_offset: int = 0

parse_synctex(synctex_path, *, strip_prefix='')

Parse a SyncTeX file (.synctex or .synctex.gz).

Parameters:

Name Type Description Default
synctex_path str

Path to the SyncTeX file.

required
strip_prefix str

Prefix to strip from input file paths. For Docker builds this is typically "/workspace/".

''

Returns:

Type Description
SyncTeXData

Parsed SyncTeX data for use with :func:inverse_search.

Raises:

Type Description
FileNotFoundError

If the file does not exist.

ValueError

If the file cannot be parsed.

Source code in synctex/synctex.py
def parse_synctex(
    synctex_path: str,
    *,
    strip_prefix: str = "",
) -> SyncTeXData:
    """Parse a SyncTeX file (.synctex or .synctex.gz).

    Args:
        synctex_path: Path to the SyncTeX file.
        strip_prefix: Prefix to strip from input file paths.
            For Docker builds this is typically ``"/workspace/"``.

    Returns:
        Parsed SyncTeX data for use with :func:`inverse_search`.

    Raises:
        FileNotFoundError: If the file does not exist.
        ValueError: If the file cannot be parsed.
    """
    content = _read_synctex(synctex_path)
    return _parse_content(content, strip_prefix=strip_prefix)

Find the source location for a point on a PDF page.

Parameters:

Name Type Description Default
data SyncTeXData

Parsed SyncTeX data from :func:parse_synctex.

required
page int

1-based page number.

required
x float

Horizontal position in PDF points (72 DPI), from the left edge.

required
y float

Vertical position in PDF points (72 DPI), from the top edge.

required

Returns:

Type Description
dict[str, str | int] | None

A dict {"file": "...", "line": N} on success, or None

dict[str, str | int] | None

if no matching source location is found.

Source code in synctex/synctex.py
def inverse_search(
    data: SyncTeXData,
    page: int,
    x: float,
    y: float,
) -> dict[str, str | int] | None:
    """Find the source location for a point on a PDF page.

    Args:
        data: Parsed SyncTeX data from :func:`parse_synctex`.
        page: 1-based page number.
        x: Horizontal position in PDF points (72 DPI), from the left edge.
        y: Vertical position in PDF points (72 DPI), from the top edge.

    Returns:
        A dict ``{"file": "...", "line": N}`` on success, or ``None``
        if no matching source location is found.
    """
    boxes = data.pages.get(page)
    if not boxes:
        return None

    # Convert PDF points to scaled points
    scale = data.unit * data.magnification / 1000.0
    if scale == 0:
        scale = 1.0
    target_x = int(x * _BP_TO_SP / scale) + data.x_offset
    target_y = int(y * _BP_TO_SP / scale) + data.y_offset

    best = _find_closest_hbox(boxes, target_x, target_y)
    if best is None:
        return None

    file_path = data.inputs.get(best.tag)
    if file_path is None:
        return None

    return {"file": file_path, "line": best.line}

Find the PDF position for a source file and line number.

Parameters:

Name Type Description Default
data SyncTeXData

Parsed SyncTeX data from :func:parse_synctex.

required
file str

Source file path (relative, as stored in data.inputs).

required
line int

1-based line number in the source file.

required

Returns:

Type Description
dict[str, int | float] | None

A dict {"page": N, "x": float, "y": float} with coordinates

dict[str, int | float] | None

in PDF points (72 DPI) on success, or None if no matching

dict[str, int | float] | None

position is found.

Source code in synctex/synctex.py
def forward_search(
    data: SyncTeXData,
    file: str,
    line: int,
) -> dict[str, int | float] | None:
    """Find the PDF position for a source file and line number.

    Args:
        data: Parsed SyncTeX data from :func:`parse_synctex`.
        file: Source file path (relative, as stored in ``data.inputs``).
        line: 1-based line number in the source file.

    Returns:
        A dict ``{"page": N, "x": float, "y": float}`` with coordinates
        in PDF points (72 DPI) on success, or ``None`` if no matching
        position is found.
    """
    # Reverse-lookup: find all tags that map to this file
    tags = {tag for tag, path in data.inputs.items() if path == file}
    if not tags:
        return None

    scale = data.unit * data.magnification / 1000.0
    if scale == 0:
        scale = 1.0

    # Search all pages for matching hboxes
    best_box: HBox | None = None
    best_page: int = 0
    best_line_dist: int = -1

    for page_num, boxes in data.pages.items():
        for box in boxes:
            if box.tag not in tags:
                continue
            dist = abs(box.line - line)
            if best_box is None or dist < best_line_dist:
                best_box = box
                best_page = page_num
                best_line_dist = dist
                if dist == 0:
                    break  # exact match on this page
        if best_line_dist == 0:
            break  # exact match found

    if best_box is None:
        return None

    # Convert scaled points back to PDF points
    pdf_x = (best_box.x - data.x_offset) * scale / _BP_TO_SP
    pdf_y = (best_box.y - data.y_offset) * scale / _BP_TO_SP

    return {"page": best_page, "x": round(pdf_x, 2), "y": round(pdf_y, 2)}