Skip to content

Add a pure-Rust makeindex engine and run it in the processing pipeline - #1404

Draft
yuhuishi-convect wants to merge 4 commits into
tectonic-typesetting:masterfrom
yuhuishi-convect:makeindex-support
Draft

yuhuishi-convect wants to merge 4 commits into
tectonic-typesetting:masterfrom
yuhuishi-convect:makeindex-support

Conversation

@yuhuishi-convect

@yuhuishi-convect yuhuishi-convect commented Oct 18, 2026 •

Copy link
Copy Markdown

Summary

This is an initial, clean-room implementation of makeindex as a new Tectonic engine crate, plus driver integration. It addresses the lack of index support discussed in #115, and provides the external index pass that #704 (glossaries) and #875 (nomencl) currently work around manually.

The implementation is written from the documented makeindex input/output formats and the makeindex manual. It does not copy the MakeIndex C source or the unlicensed c2rust port, so it can be distributed under Tectonic's MIT license.

Review guide

The branch is intentionally split into reviewable commits:

  1. Add a pure-Rust makeindex engine — the new crate, no driver changes.
  2. Run makeindex after each TeX pass — .idx → .ind only.
  3. Run makeindex for nomencl and glossaries indexes — .nlo, .glo, .acn mapping.
  4. Review polish — ownership/test cleanups.

If the full change is too large for one PR, I'm happy to split it into stacked PRs: engine crate first, then .idx integration, then nomencl/glossaries.

What it does

  • Adds crates/engine_makeindex (tectonic_engine_makeindex), a pure-Rust .idx → .ind processor.
  • Parses makeindex .ist files, including the directives used by nomencl.ist and the style files generated by glossaries.
  • Supports:
    • \indexentry{...}{...} and configurable keywords
    • @ actual/sort keys, ! subitems (3 levels), quote/escape characters
    • page encapsulators (\textbf{...}, see{...}, explicit |( / |) ranges)
    • page de-duplication, numeric/roman/alphabetic page ordering, and page-range compression
    • group headings (headings_flag, lethead_*) and the item_01/item_x1/item_12/item_x2 transitions
  • Integrates into ProcessingSession::default_pass:
    • runs after each TeX pass
    • handles .idx → .ind
    • handles .nlo → .nls with nomencl.ist
    • handles .glo → .gls and .acn → .acr with the generated <jobname>.ist
    • reruns TeX when an index output changes
    • keeps .ind/.nls/.gls/.acr as intermediates, and .ilg as a log

Validation

  • cargo test -p tectonic_engine_makeindex — 9 tests covering nested entries, transition commands, page ranges, encapsulators, style escapes, nomencl and glossaries styles.
  • cargo test -p tectonic --lib makeindex_tests — extension mapping.
  • Manually validated the full driver on three documents:
    • plain \makeindex/\printindex: index appears in the PDF
    • nomencl: nomenclature appears in the PDF
    • glossaries: glossary appears in the PDF
  • cargo fmt --all -- --check passes.
  • cargo clippy -p tectonic_engine_makeindex --all-targets is clean.

Current scope / follow-ups

This is deliberately a first step, not full makeindex parity:

  • -g German ordering, -l letter ordering, locale collation
  • output line wrapping (line_max / indent_space)
  • -p starting page numbers and .mst default-style lookup
  • composite page numbers beyond simple ranges
  • makeglossaries/bib2gls themselves (this PR only runs makeindex-style processing; bib2gls is a separate Java tool)

Happy to split this up, adjust the engine API, or extend any of the above. Since CONTRIBUTING asks for design discussion before substantial changes, I'm opening this as a draft for feedback.

Fixes #115.

Avoid cloning generated index bytes when storing them, tighten the nomencl assertion, and keep the driver changes split into reviewable commits.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tectonic does not handle packages requiring makeindex to be run

1 participant