rxiv-maker 1.18.1__tar.gz → 1.18.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/CHANGELOG.md +38 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/PKG-INFO +1 -1
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/__version__.py +1 -1
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/converters/table_processor.py +61 -32
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/exporters/docx_content_processor.py +2 -2
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/exporters/docx_exporter.py +3 -2
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/exporters/docx_writer.py +287 -61
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/cli/test_changelog_command.py +22 -2
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/.gitignore +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/LICENSE +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/README.md +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/pyproject.toml +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/docs/api/README.md +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/docs/api/index.md +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/logo/logo-rxiv-maker.afdesign +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/logo/logo-rxiv-maker.png +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/logo/logo-rxiv-maker.svg +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/__main__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/commands/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/commands/arxiv.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/commands/bibliography.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/commands/build.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/commands/cache_management.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/commands/changelog.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/commands/check_installation.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/commands/clean.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/commands/completion.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/commands/config.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/commands/create_repo.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/commands/docx.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/commands/figures.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/commands/get_rxiv_preprint.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/commands/init.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/commands/install_deps.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/commands/repo_init.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/commands/repos.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/commands/repos_search.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/commands/setup.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/commands/track_changes.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/commands/upgrade.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/commands/validate.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/commands/version.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/framework/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/framework/base.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/framework/cache_commands.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/framework/config_commands.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/framework/content_commands.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/framework/decorators.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/framework/utility_commands.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/framework/workflow_commands.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/framework.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/interactive.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/interactive_prompts.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/cli/main.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/config/defaults.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/config/validator.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/converters/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/converters/citation_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/converters/code_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/converters/comment_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/converters/custom_command_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/converters/figure_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/converters/html_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/converters/list_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/converters/math_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/converters/md2tex.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/converters/python_executor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/converters/section_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/converters/supplementary_note_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/converters/text_formatters.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/converters/types.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/converters/url_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/cache/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/cache/advanced_cache.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/cache/bibliography_cache.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/cache/cache_utils.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/cache/doi_cache.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/cache/secure_cache_utils.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/content_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/environment_bootstrap.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/environment_manager.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/error_codes.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/error_recovery.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/logging_config.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/managers/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/managers/cache_manager.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/managers/config_manager.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/managers/dependency_manager.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/managers/execution_manager.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/managers/file_manager.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/managers/install_manager.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/managers/state_manager.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/managers/unified_config_manager.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/managers/validation_manager.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/managers/workflow_manager.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/path_manager.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/progress_framework.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/repo_config.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/repository.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/session_optimizer.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/core/validation_framework.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/data/tips.yaml +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/engines/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/engines/operations/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/engines/operations/add_bibliography.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/engines/operations/build_manager.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/engines/operations/cleanup.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/engines/operations/fix_bibliography.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/engines/operations/generate_docs.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/engines/operations/generate_figures.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/engines/operations/generate_preprint.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/engines/operations/prepare_arxiv.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/engines/operations/setup_environment.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/engines/operations/track_changes.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/engines/operations/validate.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/engines/operations/validate_pdf.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/exporters/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/exporters/docx_citation_mapper.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/install/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/install/dependency_handlers/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/install/dependency_handlers/latex.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/install/dependency_handlers/r_lang.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/install/dependency_handlers/system_libs.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/install/platform_installers/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/install/platform_installers/base.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/install/platform_installers/linux.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/install/platform_installers/macos.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/install/platform_installers/windows.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/install/utils/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/install/utils/logging.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/install/utils/progress.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/install/utils/verification.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/manuscript_utils/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/manuscript_utils/figure_utils.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/processors/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/processors/author_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/processors/markdown_preprocessor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/processors/template_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/processors/yaml_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/rxiv_maker_cli.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/scripts/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/scripts/custom_doc_generator.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/scripts/validate_manuscript.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/services/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/services/base.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/services/build_service.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/services/configuration_service.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/services/manuscript_service.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/services/publication_service.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/services/validation_service.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/templates/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/templates/manager.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/templates/registry.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/tex/python_execution_section.tex +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/accent_character_map.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/author_affiliation_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/author_name_formatter.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/bibliography_checksum.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/bibliography_parser.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/bst_generator.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/changelog_parser.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/citation_range_formatter.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/citation_utils.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/comment_filter.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/dependency_checker.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/docx_helpers.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/doi_resolver.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/email_encoder.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/figure_checksum.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/file_helpers.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/github.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/homebrew_checker.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/install_detector.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/label_extractor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/operation_ids.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/pdf_splitter.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/pdf_utils.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/performance.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/platform.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/python_execution_reporter.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/retry.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/rich_upgrade_notifier.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/text_utils.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/tips.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/title_sync.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/unicode_safe.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/update_checker.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/utils/url_to_doi.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/validate.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/validators/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/validators/base_validator.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/validators/citation_validator.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/validators/doi/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/validators/doi/api_clients.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/validators/doi/metadata_comparator.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/validators/doi_validator.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/validators/figure_validator.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/validators/latex_error_parser.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/validators/math_validator.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/validators/pdf_validator.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/validators/reference_validator.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/rxiv_maker/validators/syntax_validator.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/tex/style/rxiv_maker_style.bst +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/tex/style/rxiv_maker_style.cls +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/src/tex/template.tex +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/cli/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/cli/test_build.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/cli/test_init_command.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/cli/test_main.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/conftest.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/e2e/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/e2e/test_dummy_manuscript_generator.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/e2e/test_figure_workflow_validation.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/fixtures/00_CONFIG.yml +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/fixtures/01_MAIN.md +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/fixtures/03_REFERENCES.bib +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/fixtures/FIGURES/Fig1.png +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/fixtures/FIGURES/Fig2.png +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/fixtures/FIGURES/Fig3.png +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/fixtures/README.md +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/fixtures/docx_export/sample_manuscript/01_MAIN.md +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/fixtures/docx_export/sample_manuscript/02_SUPPLEMENTARY_INFO.md +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/fixtures/docx_export/sample_manuscript/03_REFERENCES.bib +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/fixtures/docx_export/sample_manuscript/2025__unknown_et_al__rxiv.docx +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/fixtures/docx_export/sample_manuscript/sample_manuscript.docx +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/test_article_generation.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/test_bibliography_author_format_docx.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/test_binary_distribution.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/test_centralized_components.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/test_citation_injection.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/test_comment_system_integration.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/test_docx_export_integration.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/test_doi_fallback_integration.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/test_doi_validation_integration.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/test_example_manuscript.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/test_guillaume_fixtures.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/test_homebrew_workflow_validation.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/test_infrastructure_suite.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/test_init_build_workflow.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/test_install_verification_integration.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/test_latex_dependency_integration.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/test_manuscript_directory_integration.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/test_manuscript_python_execution_reporting.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/test_practical_manuscript_workflows.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/test_pypi_package_integration.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/test_python_execution_integration.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/test_repository_cli_integration.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/test_supplementary_formatting.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/test_user_reported_issue.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/integration/test_validation_workflow.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/regression/README.md +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/regression/conftest.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/regression/test_cli_argument_parsing.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/regression/test_discord_reported_issues.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/regression/test_error_message_quality.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/regression/test_google_colab_integration.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/regression/test_guillaume_edge_cases.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/regression/test_guillaume_pr131_rewrite.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/regression/test_path_resolution.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/regression/test_widget_author_behavior.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/regression/test_widget_interactions_playwright.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/smoke/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/smoke/test_basic_functionality.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/smoke/test_cli_smoke.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/system/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/system/test_ci_matrix.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/system/test_cli_workflows.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/system/test_end_to_end.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/test_homebrew_checker.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/test_install_detector.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/exporters/__init__.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/exporters/test_docx_citation_mapper.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/exporters/test_docx_content_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_add_bibliography.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_arxiv_command.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_async_execution_manager.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_author_name_formatter.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_author_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_bst_generator.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_build_command.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_build_manager.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_build_manager_manuscript_path.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_cache_security.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_cache_utils.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_check_installation_command.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_citation_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_citation_rendering.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_citation_style.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_citation_utils.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_cli_cleanup_integration.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_cli_structure.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_comment_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_conda_installation_manager.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_conda_platform_detection.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_cross_platform_optimizations.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_custom_command_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_dependency_manager.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_dependency_package_names.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_docx_doi_resolution.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_docx_helpers.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_doi_fallback_system.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_doi_resolver.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_doi_validator.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_email_encoder.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_environment_manager.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_error_handling_scenarios.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_execution_manager_comprehensive.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_figure_generator.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_figure_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_figure_processor_error_handling.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_file_helpers.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_fix_bibliography.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_generate_docs.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_generate_preprint.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_github.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_github_actions_integration.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_importlib_edge_cases.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_install_platform_installers.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_install_system_libs.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_install_verification.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_interactive_path_change.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_interactive_validators.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_latex_dependency_handler.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_manuscript_figure_utils.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_manuscript_repository.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_math_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_md2tex.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_mermaid_fallback.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_path_manager.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_pdf_validator.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_platform_comprehensive.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_platform_detector.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_processor_suite.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_python_execution_reporter.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_python_executor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_release_orchestrator.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_repository_manager.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_rich_upgrade_notifier.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_rxiv_setup_command.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_security_features.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_security_scanner.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_setup_environment.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_style_file_resolution.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_supplementary_note_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_table_rotation.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_template_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_text_formatters.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_text_utils.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_tips.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_title_sync.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_title_sync_validation.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_track_changes.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_trailing_slash_regression.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_upgrade_command.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_url_to_doi.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_utils.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_validate_backticks.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_validate_command_fixed.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_validate_manuscript.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_validation_suite.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_validators.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/unit/test_yaml_processor.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/visual/README.md +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/visual/figure-positioning/00_CONFIG.yml +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/visual/figure-positioning/01_MAIN.md +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/visual/figure-positioning/03_REFERENCES.bib +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/visual/figure-positioning/FIGURES/Figure__positioning_test.png +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/visual/figure-positioning/FIGURES/Figure__positioning_test.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/visual/figure-positioning/FIGURES/ReadyFig.png +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/visual/figure-positioning/FIGURES/ReadyFig.py +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/visual/figure-positioning/README.md +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/visual/methods-placement/00_CONFIG.yml +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/visual/methods-placement/01_MAIN.md +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/visual/methods-placement/02_SUPPLEMENTARY_INFO.md +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/visual/methods-placement/03_REFERENCES.bib +0 -0
- {rxiv_maker-1.18.1 → rxiv_maker-1.18.3}/tests/visual/methods-placement/README.md +0 -0
|
@@ -7,6 +7,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.18.3] - 2026-01-07
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Image-Based Equation Rendering in DOCX**: Equations now render as high-quality LaTeX-compiled PNG images
|
|
15
|
+
- Renders equations using pdflatex and pdftoppm at 300 DPI for perfect fidelity
|
|
16
|
+
- Smart two-tier sizing: 0.22" height for simple equations, 0.32" for equations with fractions
|
|
17
|
+
- Automatic image caching in temp directory for faster regeneration
|
|
18
|
+
- Fallback to formatted text if LaTeX tools unavailable
|
|
19
|
+
- **Equation Numbering in DOCX**: Equations now display numbers on the right side matching PDF format
|
|
20
|
+
- Numbers aligned using tab stops at 6.5 inches
|
|
21
|
+
- Consistent with PDF equation numbering
|
|
22
|
+
- Equation references in text link to correct equation numbers
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- **Equation Reference Highlighting**: Changed from dark violet (hard to read) to pink for better visibility
|
|
27
|
+
- **Panel Letter Formatting**: Figure references now format as "Fig. 2f" instead of "Fig. 2 f" (no space before panel letter)
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- **Font Size Consistency in DOCX**: All text runs now explicitly set to 10pt to prevent size variations
|
|
32
|
+
- Previously subscript/superscript text lacked explicit sizing, causing inconsistent rendering
|
|
33
|
+
- Body text, subscripts, superscripts, and code blocks all use consistent sizing
|
|
34
|
+
- **Subscript Pattern Matching**: Fixed false subscript formatting for tildes used as "approximately"
|
|
35
|
+
- Pattern now excludes punctuation (`,;:.!?()`) to avoid matching across sentences
|
|
36
|
+
- Tildes like `~4 nm` no longer incorrectly treated as subscript markers
|
|
37
|
+
|
|
38
|
+
## [1.18.2] - 2026-01-06
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- **Table Caption Parser Enhancement**: Improved robustness of table caption detection
|
|
43
|
+
- Flexible whitespace handling: Parser now skips blank lines and HTML comments between tables and captions
|
|
44
|
+
- Cross-reference support: Table captions can now include references to figures, tables, and equations
|
|
45
|
+
- Dynamic line-skipping logic: Intelligently determines how many lines to skip based on actual content
|
|
46
|
+
- Fixes issues where captions separated from tables by comments or extra whitespace were not detected
|
|
47
|
+
|
|
10
48
|
## [1.18.1] - 2024-12-24
|
|
11
49
|
|
|
12
50
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rxiv-maker
|
|
3
|
-
Version: 1.18.
|
|
3
|
+
Version: 1.18.3
|
|
4
4
|
Summary: Write scientific preprints in Markdown. Generate publication-ready PDFs efficiently.
|
|
5
5
|
Project-URL: Homepage, https://github.com/HenriquesLab/rxiv-maker
|
|
6
6
|
Project-URL: Documentation, https://github.com/HenriquesLab/rxiv-maker#readme
|
|
@@ -139,9 +139,9 @@ def convert_tables_to_latex(
|
|
|
139
139
|
result_lines.pop() # Remove caption line
|
|
140
140
|
|
|
141
141
|
# Check for new format table caption after the table
|
|
142
|
-
new_format_caption, table_id, rotation_angle = _parse_table_caption(lines, i)
|
|
143
|
-
if new_format_caption:
|
|
144
|
-
i +=
|
|
142
|
+
new_format_caption, table_id, rotation_angle, lines_to_skip = _parse_table_caption(lines, i)
|
|
143
|
+
if new_format_caption and lines_to_skip:
|
|
144
|
+
i += lines_to_skip # Skip blank lines, comments, and caption line
|
|
145
145
|
|
|
146
146
|
# Generate LaTeX table with the processed caption
|
|
147
147
|
latex_table = generate_latex_table(
|
|
@@ -844,39 +844,68 @@ def _is_table_row(line: str) -> bool:
|
|
|
844
844
|
return "|" in line and line.startswith("|") and line.endswith("|")
|
|
845
845
|
|
|
846
846
|
|
|
847
|
-
def _parse_table_caption(lines: list[str], i: int) -> tuple[str | None, str | None, int | None]:
|
|
848
|
-
"""Parse table caption in new format after table.
|
|
847
|
+
def _parse_table_caption(lines: list[str], i: int) -> tuple[str | None, str | None, int | None, int | None]:
|
|
848
|
+
"""Parse table caption in new format after table.
|
|
849
|
+
|
|
850
|
+
Returns:
|
|
851
|
+
tuple of (caption, table_id, rotation_angle, lines_to_skip)
|
|
852
|
+
lines_to_skip indicates how many lines after position i should be skipped
|
|
853
|
+
"""
|
|
849
854
|
new_format_caption = None
|
|
850
855
|
table_id = None
|
|
851
856
|
rotation_angle = None
|
|
857
|
+
lines_to_skip = None
|
|
852
858
|
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
if
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
if
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
859
|
+
# Look ahead for caption, skipping blank lines and HTML comments
|
|
860
|
+
# Search up to 5 lines ahead to be flexible
|
|
861
|
+
search_limit = min(i + 5, len(lines))
|
|
862
|
+
|
|
863
|
+
for offset in range(search_limit - i):
|
|
864
|
+
check_line = lines[i + offset].strip()
|
|
865
|
+
|
|
866
|
+
# Skip blank lines and HTML comments
|
|
867
|
+
if check_line == "" or (check_line.startswith("<!--") and check_line.endswith("-->")):
|
|
868
|
+
continue
|
|
869
|
+
|
|
870
|
+
# Check if this is a new-format caption
|
|
871
|
+
if re.match(r"^\{#[a-zA-Z0-9_:-]+.*\}\s*\*\*.*\*\*", check_line):
|
|
872
|
+
caption_line = check_line
|
|
873
|
+
|
|
874
|
+
# Parse caption with optional attributes like rotate=90
|
|
875
|
+
caption_match = re.match(r"^\{#([a-zA-Z0-9_:-]+)([^}]*)\}\s*(.+)$", caption_line)
|
|
876
|
+
if caption_match:
|
|
877
|
+
table_id = caption_match.group(1)
|
|
878
|
+
attributes_str = caption_match.group(2).strip()
|
|
879
|
+
caption_text = caption_match.group(3)
|
|
880
|
+
|
|
881
|
+
# Extract rotation attribute if present
|
|
882
|
+
if attributes_str:
|
|
883
|
+
rotation_match = re.search(r"rotate=(\d+)", attributes_str)
|
|
884
|
+
if rotation_match:
|
|
885
|
+
rotation_angle = int(rotation_match.group(1))
|
|
886
|
+
|
|
887
|
+
# Process caption text to handle markdown formatting
|
|
888
|
+
new_format_caption = re.sub(r"\*\*([^*]+)\*\*", r"\\textbf{\1}", caption_text)
|
|
889
|
+
new_format_caption = re.sub(r"\*([^*]+)\*", r"\\textit{\1}", new_format_caption)
|
|
890
|
+
|
|
891
|
+
# Convert cross-references (figures, tables, equations) in caption
|
|
892
|
+
from .figure_processor import (
|
|
893
|
+
convert_equation_references_to_latex,
|
|
894
|
+
convert_figure_references_to_latex,
|
|
895
|
+
)
|
|
896
|
+
|
|
897
|
+
new_format_caption = convert_figure_references_to_latex(new_format_caption)
|
|
898
|
+
new_format_caption = convert_table_references_to_latex(new_format_caption)
|
|
899
|
+
new_format_caption = convert_equation_references_to_latex(new_format_caption)
|
|
900
|
+
|
|
901
|
+
# Return how many lines to skip (all lines from i to caption, inclusive)
|
|
902
|
+
lines_to_skip = offset + 1
|
|
903
|
+
break
|
|
904
|
+
else:
|
|
905
|
+
# Found a non-blank, non-comment, non-caption line - stop searching
|
|
906
|
+
break
|
|
907
|
+
|
|
908
|
+
return new_format_caption, table_id, rotation_angle, lines_to_skip
|
|
880
909
|
|
|
881
910
|
|
|
882
911
|
def _split_table_row_respecting_backticks(row: str) -> list[str]:
|
|
@@ -375,8 +375,8 @@ class DocxContentProcessor:
|
|
|
375
375
|
r"|(__([^_]+)__)" # Underline with double underscores (must come before single underscore)
|
|
376
376
|
r"|(\*([^*]+)\*)" # Italic with asterisks
|
|
377
377
|
r"|(_([^_]+)_)" # Italic with underscores
|
|
378
|
-
r"|(~([^~]+)~)" # Subscript
|
|
379
|
-
r"|(\^([^^]+)\^)" # Superscript
|
|
378
|
+
r"|(~([^~(),;:.!?]+)~)" # Subscript (exclude punctuation to avoid matching "approximately" usage)
|
|
379
|
+
r"|(\^([^^(),;:.!?]+)\^)" # Superscript (same restriction)
|
|
380
380
|
r"|(`([^`]+)`)" # Code
|
|
381
381
|
r"|(\$([^\$]+)\$)" # Inline math
|
|
382
382
|
r"|(\[(\d+(?:[-,]\s*\d+)*)\])" # Citation numbers (supports both ranges [1-3] and lists [1, 2])
|
|
@@ -144,7 +144,7 @@ class DocxExporter:
|
|
|
144
144
|
# Panel letters must be followed by non-letter (space, punctuation, end of string)
|
|
145
145
|
markdown_with_numbers = re.sub(
|
|
146
146
|
rf"@fig:{label}\b(\s+[a-z](?:[,\-][a-z])*(?![a-z]))?",
|
|
147
|
-
lambda m, num=num: f"<<XREF:fig>>Fig. {num}{m.group(1) if m.group(1) else ''}<</XREF>>",
|
|
147
|
+
lambda m, num=num: f"<<XREF:fig>>Fig. {num}{m.group(1).strip() if m.group(1) else ''}<</XREF>>",
|
|
148
148
|
markdown_with_numbers,
|
|
149
149
|
)
|
|
150
150
|
|
|
@@ -161,7 +161,7 @@ class DocxExporter:
|
|
|
161
161
|
# Negative lookahead prevents matching start of words
|
|
162
162
|
markdown_with_numbers = re.sub(
|
|
163
163
|
rf"@sfig:{label}\b(\s+[a-z](?:[,\-][a-z])*(?![a-z]))?",
|
|
164
|
-
lambda m, num=num: f"<<XREF:sfig>>Supp. Fig. {num}{m.group(1) if m.group(1) else ''}<</XREF>>",
|
|
164
|
+
lambda m, num=num: f"<<XREF:sfig>>Supp. Fig. {num}{m.group(1).strip() if m.group(1) else ''}<</XREF>>",
|
|
165
165
|
markdown_with_numbers,
|
|
166
166
|
)
|
|
167
167
|
|
|
@@ -230,6 +230,7 @@ class DocxExporter:
|
|
|
230
230
|
base_path=self.path_manager.manuscript_path,
|
|
231
231
|
metadata=metadata,
|
|
232
232
|
table_map=table_map,
|
|
233
|
+
equation_map=equation_map,
|
|
233
234
|
figures_at_end=self.figures_at_end,
|
|
234
235
|
hide_highlighting=self.hide_highlighting,
|
|
235
236
|
hide_comments=self.hide_comments,
|
|
@@ -32,7 +32,7 @@ class DocxWriter:
|
|
|
32
32
|
"sfig": WD_COLOR_INDEX.TURQUOISE, # Supplementary figures (turquoise - lighter cyan)
|
|
33
33
|
"stable": WD_COLOR_INDEX.TURQUOISE, # Supplementary tables (turquoise - lighter cyan)
|
|
34
34
|
"table": WD_COLOR_INDEX.BLUE, # Main tables
|
|
35
|
-
"eq": WD_COLOR_INDEX.
|
|
35
|
+
"eq": WD_COLOR_INDEX.PINK, # Equations (pink - lighter than violet, easier to read)
|
|
36
36
|
"snote": WD_COLOR_INDEX.TURQUOISE, # Supplementary notes (turquoise - lighter cyan)
|
|
37
37
|
"cite": WD_COLOR_INDEX.YELLOW, # Citations (yellow)
|
|
38
38
|
}
|
|
@@ -58,6 +58,7 @@ class DocxWriter:
|
|
|
58
58
|
base_path: Optional[Path] = None,
|
|
59
59
|
metadata: Optional[Dict[str, Any]] = None,
|
|
60
60
|
table_map: Optional[Dict[str, int]] = None,
|
|
61
|
+
equation_map: Optional[Dict[str, int]] = None,
|
|
61
62
|
figures_at_end: bool = False,
|
|
62
63
|
hide_highlighting: bool = False,
|
|
63
64
|
hide_comments: bool = False,
|
|
@@ -72,6 +73,7 @@ class DocxWriter:
|
|
|
72
73
|
base_path: Base path for resolving relative figure paths
|
|
73
74
|
metadata: Document metadata (title, authors, affiliations)
|
|
74
75
|
table_map: Mapping from table labels to numbers (for supplementary tables)
|
|
76
|
+
equation_map: Mapping from equation labels to numbers
|
|
75
77
|
figures_at_end: Place main figures at end before SI/bibliography
|
|
76
78
|
hide_highlighting: Disable colored highlighting on references and citations
|
|
77
79
|
hide_comments: Exclude all comments (block and inline) from output
|
|
@@ -83,6 +85,7 @@ class DocxWriter:
|
|
|
83
85
|
self.bibliography = bibliography
|
|
84
86
|
self.include_footnotes = include_footnotes
|
|
85
87
|
self.table_map = table_map or {}
|
|
88
|
+
self.equation_map = equation_map or {}
|
|
86
89
|
self.hide_highlighting = hide_highlighting
|
|
87
90
|
self.hide_comments = hide_comments
|
|
88
91
|
doc = Document()
|
|
@@ -464,6 +467,9 @@ class DocxWriter:
|
|
|
464
467
|
text = run_data["text"]
|
|
465
468
|
run = paragraph.add_run(text)
|
|
466
469
|
|
|
470
|
+
# Always set font size explicitly for consistency (body text is 10pt)
|
|
471
|
+
run.font.size = Pt(10)
|
|
472
|
+
|
|
467
473
|
# Apply formatting
|
|
468
474
|
if run_data.get("bold"):
|
|
469
475
|
run.bold = True
|
|
@@ -477,7 +483,7 @@ class DocxWriter:
|
|
|
477
483
|
run.font.superscript = True
|
|
478
484
|
if run_data.get("code"):
|
|
479
485
|
run.font.name = "Courier New"
|
|
480
|
-
|
|
486
|
+
# Font size already set to Pt(10) above
|
|
481
487
|
if run_data.get("xref"):
|
|
482
488
|
# Use color based on xref type (fig, sfig, stable, eq, etc.)
|
|
483
489
|
xref_type = run_data.get("xref_type", "cite")
|
|
@@ -533,6 +539,9 @@ class DocxWriter:
|
|
|
533
539
|
text = run_data["text"]
|
|
534
540
|
run = paragraph.add_run(text)
|
|
535
541
|
|
|
542
|
+
# Always set font size explicitly for consistency (body text is 10pt)
|
|
543
|
+
run.font.size = Pt(10)
|
|
544
|
+
|
|
536
545
|
# Apply formatting
|
|
537
546
|
if run_data.get("bold"):
|
|
538
547
|
run.bold = True
|
|
@@ -544,15 +553,13 @@ class DocxWriter:
|
|
|
544
553
|
run.font.superscript = True
|
|
545
554
|
if run_data.get("code"):
|
|
546
555
|
run.font.name = "Courier New"
|
|
556
|
+
# Font size already set to Pt(10) above
|
|
547
557
|
if run_data.get("xref"):
|
|
548
558
|
# Use color based on xref type
|
|
549
559
|
xref_type = run_data.get("xref_type", "cite")
|
|
550
560
|
self._apply_highlight(run, self.get_xref_color(xref_type))
|
|
551
561
|
if run_data.get("highlight_yellow"):
|
|
552
562
|
self._apply_highlight(run, WD_COLOR_INDEX.YELLOW)
|
|
553
|
-
run.font.size = Pt(10)
|
|
554
|
-
if run_data.get("highlight_yellow"):
|
|
555
|
-
self._apply_highlight(run, WD_COLOR_INDEX.YELLOW)
|
|
556
563
|
elif run_data["type"] == "hyperlink":
|
|
557
564
|
text = run_data.get("text", "")
|
|
558
565
|
url = run_data.get("url", "")
|
|
@@ -975,7 +982,7 @@ class DocxWriter:
|
|
|
975
982
|
run.font.size = Pt(10)
|
|
976
983
|
|
|
977
984
|
def _add_equation(self, doc: Document, section: Dict[str, Any]):
|
|
978
|
-
"""Add equation to document as
|
|
985
|
+
"""Add equation to document as rendered image with numbering.
|
|
979
986
|
|
|
980
987
|
Args:
|
|
981
988
|
doc: Document object
|
|
@@ -984,75 +991,294 @@ class DocxWriter:
|
|
|
984
991
|
import re
|
|
985
992
|
|
|
986
993
|
latex_content = section.get("content", "")
|
|
987
|
-
|
|
994
|
+
label = section.get("label", "") # e.g., "eq:bernoulli_labeling"
|
|
988
995
|
|
|
989
996
|
if not latex_content:
|
|
990
997
|
return
|
|
991
998
|
|
|
999
|
+
# Get equation number from label
|
|
1000
|
+
equation_number = None
|
|
1001
|
+
if label:
|
|
1002
|
+
# Extract label name (e.g., "eq:bernoulli_labeling" -> "bernoulli_labeling")
|
|
1003
|
+
label_name = label.split(":", 1)[1] if ":" in label else label
|
|
1004
|
+
equation_number = self.equation_map.get(label_name)
|
|
1005
|
+
|
|
1006
|
+
# Create a paragraph for the equation
|
|
1007
|
+
para = doc.add_paragraph()
|
|
1008
|
+
para.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
|
1009
|
+
|
|
1010
|
+
# Try to render equation as image
|
|
992
1011
|
try:
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
r"\\
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
+
equation_img = self._render_equation_to_image(latex_content)
|
|
1013
|
+
if equation_img and equation_img.exists():
|
|
1014
|
+
# Add equation image with two-tier sizing
|
|
1015
|
+
run = para.add_run()
|
|
1016
|
+
import re
|
|
1017
|
+
|
|
1018
|
+
from docx.shared import Inches
|
|
1019
|
+
|
|
1020
|
+
# Detect if equation has fractions or other vertical elements
|
|
1021
|
+
has_fractions = bool(re.search(r"\\frac|\\dfrac", latex_content))
|
|
1022
|
+
|
|
1023
|
+
# Simple two-tier sizing:
|
|
1024
|
+
# - Equations with fractions: 0.32 inches (taller for readability)
|
|
1025
|
+
# - Simple equations without fractions: 0.22 inches (consistent with text)
|
|
1026
|
+
if has_fractions:
|
|
1027
|
+
run.add_picture(str(equation_img), height=Inches(0.32))
|
|
1028
|
+
logger.debug("Equation with fractions: height=0.32in")
|
|
1029
|
+
else:
|
|
1030
|
+
run.add_picture(str(equation_img), height=Inches(0.22))
|
|
1031
|
+
logger.debug("Simple equation: height=0.22in")
|
|
1012
1032
|
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1033
|
+
logger.info(f"Equation rendered as image: {equation_img}")
|
|
1034
|
+
else:
|
|
1035
|
+
# Fallback to formatted text
|
|
1036
|
+
logger.warning("Failed to render equation as image, using formatted text")
|
|
1037
|
+
self._render_latex_formatted(para, latex_content)
|
|
1038
|
+
except Exception as e:
|
|
1039
|
+
logger.warning(f"Equation image rendering failed: {e}, using formatted text")
|
|
1040
|
+
self._render_latex_formatted(para, latex_content)
|
|
1016
1041
|
|
|
1017
|
-
|
|
1018
|
-
|
|
1042
|
+
# Add equation number on the right side if available
|
|
1043
|
+
if equation_number:
|
|
1044
|
+
# Add tab stop for right alignment
|
|
1045
|
+
from docx.enum.text import WD_TAB_ALIGNMENT
|
|
1046
|
+
from docx.shared import Inches
|
|
1019
1047
|
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
logger.debug(f"OMML element created: {type(omml_root)}")
|
|
1048
|
+
tab_stops = para.paragraph_format.tab_stops
|
|
1049
|
+
tab_stops.add_tab_stop(Inches(6.5), WD_TAB_ALIGNMENT.RIGHT)
|
|
1023
1050
|
|
|
1024
|
-
#
|
|
1025
|
-
|
|
1026
|
-
|
|
1051
|
+
# Add tab and equation number
|
|
1052
|
+
num_run = para.add_run(f"\t({equation_number})")
|
|
1053
|
+
num_run.font.size = Pt(11)
|
|
1027
1054
|
|
|
1028
|
-
|
|
1029
|
-
para._element.append(omml_root)
|
|
1030
|
-
logger.info("Equation successfully added to document")
|
|
1055
|
+
logger.info("Equation successfully added to document")
|
|
1031
1056
|
|
|
1032
|
-
|
|
1033
|
-
|
|
1057
|
+
# Add spacing after equation
|
|
1058
|
+
para.paragraph_format.space_after = Pt(12)
|
|
1034
1059
|
|
|
1035
|
-
|
|
1036
|
-
|
|
1060
|
+
def _render_equation_to_image(self, latex_content: str) -> Optional[Path]:
|
|
1061
|
+
"""Render LaTeX equation to PNG image.
|
|
1037
1062
|
|
|
1063
|
+
Args:
|
|
1064
|
+
latex_content: LaTeX equation content
|
|
1065
|
+
|
|
1066
|
+
Returns:
|
|
1067
|
+
Path to generated PNG image, or None if rendering failed
|
|
1068
|
+
"""
|
|
1069
|
+
import hashlib
|
|
1070
|
+
import subprocess
|
|
1071
|
+
import tempfile
|
|
1072
|
+
from pathlib import Path
|
|
1073
|
+
|
|
1074
|
+
# Create a hash of the equation content for caching
|
|
1075
|
+
eq_hash = hashlib.md5(latex_content.encode()).hexdigest()[:8]
|
|
1076
|
+
|
|
1077
|
+
# Use temp directory for equation images
|
|
1078
|
+
temp_dir = Path(tempfile.gettempdir()) / "rxiv_equations"
|
|
1079
|
+
temp_dir.mkdir(exist_ok=True)
|
|
1080
|
+
|
|
1081
|
+
output_png = temp_dir / f"eq_{eq_hash}.png"
|
|
1082
|
+
|
|
1083
|
+
# Check if we already rendered this equation
|
|
1084
|
+
if output_png.exists():
|
|
1085
|
+
logger.debug(f"Using cached equation image: {output_png}")
|
|
1086
|
+
return output_png
|
|
1087
|
+
|
|
1088
|
+
# Create LaTeX document for standalone equation
|
|
1089
|
+
latex_template = r"""\documentclass[preview,border=2pt]{standalone}
|
|
1090
|
+
\usepackage{amsmath}
|
|
1091
|
+
\usepackage{amssymb}
|
|
1092
|
+
\usepackage{amsfonts}
|
|
1093
|
+
\begin{document}
|
|
1094
|
+
\begin{math}
|
|
1095
|
+
\displaystyle EQUATION_CONTENT
|
|
1096
|
+
\end{math}
|
|
1097
|
+
\end{document}
|
|
1098
|
+
"""
|
|
1099
|
+
latex_doc = latex_template.replace("EQUATION_CONTENT", latex_content)
|
|
1100
|
+
|
|
1101
|
+
# Write to temporary .tex file
|
|
1102
|
+
tex_file = temp_dir / f"eq_{eq_hash}.tex"
|
|
1103
|
+
with open(tex_file, "w") as f:
|
|
1104
|
+
f.write(latex_doc)
|
|
1105
|
+
|
|
1106
|
+
try:
|
|
1107
|
+
# Compile LaTeX to PDF
|
|
1108
|
+
result = subprocess.run(
|
|
1109
|
+
["pdflatex", "-interaction=nonstopmode", "-output-directory", str(temp_dir), str(tex_file)],
|
|
1110
|
+
capture_output=True,
|
|
1111
|
+
text=True,
|
|
1112
|
+
timeout=10,
|
|
1113
|
+
)
|
|
1114
|
+
|
|
1115
|
+
if result.returncode != 0:
|
|
1116
|
+
logger.warning(f"pdflatex failed for equation: {latex_content[:50]}...")
|
|
1117
|
+
logger.debug(f"pdflatex output: {result.stdout}")
|
|
1118
|
+
return None
|
|
1119
|
+
|
|
1120
|
+
# Convert PDF to PNG using pdftoppm (high resolution for quality)
|
|
1121
|
+
pdf_file = temp_dir / f"eq_{eq_hash}.pdf"
|
|
1122
|
+
if not pdf_file.exists():
|
|
1123
|
+
logger.warning(f"PDF not generated: {pdf_file}")
|
|
1124
|
+
return None
|
|
1125
|
+
|
|
1126
|
+
# Use pdftoppm to convert to PNG at high DPI (300 for quality)
|
|
1127
|
+
result = subprocess.run(
|
|
1128
|
+
["pdftoppm", "-png", "-singlefile", "-r", "300", str(pdf_file), str(temp_dir / f"eq_{eq_hash}")],
|
|
1129
|
+
capture_output=True,
|
|
1130
|
+
text=True,
|
|
1131
|
+
timeout=10,
|
|
1132
|
+
)
|
|
1133
|
+
|
|
1134
|
+
if result.returncode != 0:
|
|
1135
|
+
logger.warning(f"pdftoppm failed: {result.stderr}")
|
|
1136
|
+
return None
|
|
1137
|
+
|
|
1138
|
+
if output_png.exists():
|
|
1139
|
+
logger.debug(f"Equation rendered to image: {output_png}")
|
|
1140
|
+
return output_png
|
|
1141
|
+
else:
|
|
1142
|
+
logger.warning(f"PNG not generated: {output_png}")
|
|
1143
|
+
return None
|
|
1144
|
+
|
|
1145
|
+
except subprocess.TimeoutExpired:
|
|
1146
|
+
logger.warning("Equation rendering timed out")
|
|
1147
|
+
return None
|
|
1148
|
+
except FileNotFoundError as e:
|
|
1149
|
+
logger.warning(f"LaTeX/pdftoppm not found: {e}")
|
|
1150
|
+
return None
|
|
1038
1151
|
except Exception as e:
|
|
1039
|
-
logger.warning(f"Equation rendering
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
#
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1152
|
+
logger.warning(f"Equation rendering error: {e}")
|
|
1153
|
+
return None
|
|
1154
|
+
finally:
|
|
1155
|
+
# Clean up intermediate files
|
|
1156
|
+
for ext in [".tex", ".pdf", ".aux", ".log"]:
|
|
1157
|
+
temp_file = temp_dir / f"eq_{eq_hash}{ext}"
|
|
1158
|
+
if temp_file.exists():
|
|
1159
|
+
try:
|
|
1160
|
+
temp_file.unlink()
|
|
1161
|
+
except Exception:
|
|
1162
|
+
pass
|
|
1163
|
+
|
|
1164
|
+
def _render_latex_formatted(self, paragraph, latex_content: str):
|
|
1165
|
+
"""Render LaTeX equation with formatted subscripts and superscripts.
|
|
1166
|
+
|
|
1167
|
+
Args:
|
|
1168
|
+
paragraph: Paragraph object to add formatted equation to
|
|
1169
|
+
latex_content: LaTeX equation content
|
|
1170
|
+
"""
|
|
1171
|
+
import re
|
|
1172
|
+
|
|
1173
|
+
# LaTeX symbol replacements
|
|
1174
|
+
symbol_map = {
|
|
1175
|
+
r"\\sim": "~",
|
|
1176
|
+
r"\\approx": "≈",
|
|
1177
|
+
r"\\le": "≤",
|
|
1178
|
+
r"\\ge": "≥",
|
|
1179
|
+
r"\\ne": "≠",
|
|
1180
|
+
r"\\times": "×",
|
|
1181
|
+
r"\\pm": "±",
|
|
1182
|
+
r"\\in": "∈",
|
|
1183
|
+
r"\\subset": "⊂",
|
|
1184
|
+
r"\\cap": "∩",
|
|
1185
|
+
r"\\cup": "∪",
|
|
1186
|
+
r"\\mid": "|",
|
|
1187
|
+
r"\\alpha": "α",
|
|
1188
|
+
r"\\beta": "β",
|
|
1189
|
+
r"\\gamma": "γ",
|
|
1190
|
+
r"\\delta": "δ",
|
|
1191
|
+
r"\\epsilon": "ε",
|
|
1192
|
+
r"\\theta": "θ",
|
|
1193
|
+
r"\\lambda": "λ",
|
|
1194
|
+
r"\\sigma": "σ",
|
|
1195
|
+
r"\\mu": "μ",
|
|
1196
|
+
r"\\pi": "π",
|
|
1197
|
+
r"\\sum": "Σ",
|
|
1198
|
+
r"\\prod": "Π",
|
|
1199
|
+
r"\\int": "∫",
|
|
1200
|
+
r"\\infty": "∞",
|
|
1201
|
+
r"\\mathbb\{I\}": "𝕀",
|
|
1202
|
+
r"\\mathbb\{R\}": "ℝ",
|
|
1203
|
+
r"\\mathbb\{N\}": "ℕ",
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
# Replace LaTeX commands with symbols
|
|
1207
|
+
content = latex_content
|
|
1208
|
+
for latex_cmd, symbol in symbol_map.items():
|
|
1209
|
+
content = re.sub(latex_cmd, symbol, content)
|
|
1210
|
+
|
|
1211
|
+
# Remove \text{} wrappers but keep content
|
|
1212
|
+
content = re.sub(r"\\text\{([^}]+)\}", r"\1", content)
|
|
1213
|
+
|
|
1214
|
+
# Remove \left and \right sizing commands
|
|
1215
|
+
content = re.sub(r"\\left|\\right", "", content)
|
|
1216
|
+
|
|
1217
|
+
# Remove \mathbf{} but keep content (for now, just remove formatting)
|
|
1218
|
+
content = re.sub(r"\\mathbf\{([^}]+)\}", r"\1", content)
|
|
1219
|
+
|
|
1220
|
+
# Parse and render with subscripts/superscripts
|
|
1221
|
+
# Pattern: text followed by _{subscript} or ^{superscript}
|
|
1222
|
+
i = 0
|
|
1223
|
+
while i < len(content):
|
|
1224
|
+
if content[i] == "_" and i + 1 < len(content):
|
|
1225
|
+
# Subscript
|
|
1226
|
+
if content[i + 1] == "{":
|
|
1227
|
+
# Find matching brace
|
|
1228
|
+
brace_end = content.find("}", i + 2)
|
|
1229
|
+
if brace_end != -1:
|
|
1230
|
+
sub_text = content[i + 2 : brace_end]
|
|
1231
|
+
run = paragraph.add_run(sub_text)
|
|
1232
|
+
run.font.subscript = True
|
|
1233
|
+
run.font.size = Pt(11)
|
|
1234
|
+
i = brace_end + 1
|
|
1235
|
+
continue
|
|
1236
|
+
else:
|
|
1237
|
+
# Single character subscript
|
|
1238
|
+
run = paragraph.add_run(content[i + 1])
|
|
1239
|
+
run.font.subscript = True
|
|
1240
|
+
run.font.size = Pt(11)
|
|
1241
|
+
i += 2
|
|
1242
|
+
continue
|
|
1243
|
+
|
|
1244
|
+
elif content[i] == "^" and i + 1 < len(content):
|
|
1245
|
+
# Superscript
|
|
1246
|
+
if content[i + 1] == "{":
|
|
1247
|
+
# Find matching brace
|
|
1248
|
+
brace_end = content.find("}", i + 2)
|
|
1249
|
+
if brace_end != -1:
|
|
1250
|
+
sup_text = content[i + 2 : brace_end]
|
|
1251
|
+
run = paragraph.add_run(sup_text)
|
|
1252
|
+
run.font.superscript = True
|
|
1253
|
+
run.font.size = Pt(11)
|
|
1254
|
+
i = brace_end + 1
|
|
1255
|
+
continue
|
|
1256
|
+
else:
|
|
1257
|
+
# Single character superscript
|
|
1258
|
+
run = paragraph.add_run(content[i + 1])
|
|
1259
|
+
run.font.superscript = True
|
|
1260
|
+
run.font.size = Pt(11)
|
|
1261
|
+
i += 2
|
|
1262
|
+
continue
|
|
1263
|
+
|
|
1264
|
+
# Regular text
|
|
1265
|
+
# Collect text until next special character
|
|
1266
|
+
text_chunk = ""
|
|
1267
|
+
while i < len(content) and content[i] not in ["_", "^", "\\"]:
|
|
1268
|
+
text_chunk += content[i]
|
|
1269
|
+
i += 1
|
|
1270
|
+
|
|
1271
|
+
if text_chunk:
|
|
1272
|
+
run = paragraph.add_run(text_chunk)
|
|
1273
|
+
run.font.size = Pt(11)
|
|
1274
|
+
run.font.italic = True # Math content is typically italic
|
|
1275
|
+
|
|
1276
|
+
# Handle backslash commands we didn't replace
|
|
1277
|
+
if i < len(content) and content[i] == "\\":
|
|
1278
|
+
# Skip the backslash and next word
|
|
1279
|
+
i += 1
|
|
1280
|
+
while i < len(content) and content[i].isalpha():
|
|
1281
|
+
i += 1
|
|
1056
1282
|
|
|
1057
1283
|
def _mathml_to_omml(self, mathml_elem):
|
|
1058
1284
|
"""Convert MathML to OMML (Office Math Markup Language).
|