# GhostEditor / md2gost — полное описание проекта Версия пакета: **0.1.0**. Python **≥ 3.10**. Репозиторий: конвертер учебных отчётов **Markdown → DOCX** по методичке РТУ МИРЭА (ГОСТ 7.32-2017) и профилям **ПИС / АПИД**. Рядом — два дополнительных пайплайна: **FODT** (LibreOffice) и **LaTeX → PDF**. Этот файл — карта всего репозитория: что уже работает, как устроен код, какие функции есть в CLI/GUI и какие модули за что отвечают. Пользовательская документация по разделам лежит в [`docs/`](docs/). --- ## 1. Зачем проект существует Студент пишет отчёт в расширенном Markdown (диалект md2gost). Конвертер сам: - оформляет DOCX стилями Times New Roman, полями 30/10/20/20 мм, интервалом 1.5; - нумерует рисунки, таблицы, листинги, формулы; - собирает содержание и список источников; - рисует UML / C4 / Mermaid; - проверяет структуру по ТЗ (`--check`); - при необходимости режет длинные таблицы и листинги через Microsoft Word и пишет «Продолжение…». Исходный форк: [benzlokzik/md2gost](https://github.com/benzlokzik/md2gost). Здесь — своя линия: профили МИРЭА/ПИС/АПИД, GUI, схемы, стили JSON, Word COM, FODT, LaTeX. --- ## 2. Три продукта в одном репозитории | Пакет | Entry point | Результат | Когда | |--------|-------------|-----------|--------| | **md2gost** | `python -m md2gost` / `md2gost-gui` | `.docx` | основной путь, Word | | **md2fodt** | `python -m md2fodt` | `.fodt` | LibreOffice, без Word | | **md2latex** | `python -m md2latex` | каталог XeLaTeX (+ `--pdf`) | PDF через шаблон МИРЭА | | **word2md** | `python -m word2md` / `md2gost файл.docx` | `.md` | импорт DOCX → диалект md2gost | Общий диалект разметки: спецразделы `# *ВВЕДЕНИЕ`, метки `%id`, ссылки `@Рисунок:id`, таблицы с `^`/`>`, формулы `$$`, библиография `[n]: …`. Полнота реализации **не одинаковая**: - **md2gost** — полный конвейер (стили, профили, диаграммы, checker, GUI, Word COM). - **md2fodt** — v1: текст, заголовки, списки, таблицы с merge, картинки, листинги, простые ссылки, библиография. Нет PlantUML, нет «Продолжение таблицы», нет полного паритета PIS/АПИД. - **md2latex** — тот же диалект → `content.tex` + копия `latex/mirea/`. Таблицы идут в `longtable` с настоящим «Продолжение таблицы N» (это умеет LaTeX, не Word). - **word2md** — эвристический DOCX → диалект md2gost (стили Caption/Heading, подписи, таблицы, Code, формулы OMML). Не восстанавливает UML/Mermaid и исходные `%id`. --- ## 3. Как запустить ```bash pip install -e . python -m md2gost # GUI python -m md2gost report.md -o report.docx --type coursework --check python -m word2md report.docx -o report.md python -m md2fodt report.md -o report.fodt python -m md2latex report.md -o report_latex --pdf ``` Windows exe: `build-exe.bat` → `dist\md2gost.exe` (двойной клик — GUI; из консоли работает как CLI; перед сборкой тянет plantuml.jar и portable Graphviz). Быстрая сборка: `build-exe-fast.bat` + `md2gost.fast.spec`. Для режима продолжения таблиц/листингов `word` (по умолчанию): Windows + Microsoft Word + `pip install pywin32` (опциональная группа `[word]`). --- ## 4. Архитектура md2gost (главный конвейер) Один движок на CLI и GUI. GUI только собирает `ConvertRequest` и зовёт `convert()`. ``` .md │ ├─ checker.check_markdown() # если --check / --check-only │ ├─ profiles.preprocess_markdown() # «ёлочки», тире; не трогает UML/Mermaid │ ├─ Parser (marko + extended_markdown) │ └─ RenderableFactory → список Renderable │ ├─ biblio_processor.fold_bibliography() ├─ Heading / ToC / Table / Listing: режимы нумерации и continuation ├─ label_pass.assign_numbers() + resolve @Тип:id │ ├─ Renderer.process() # LayoutTracker, секции, альбом, колонтитулы ├─ TocProcessor.process() # native TOC field или ручная сборка │ ├─ [опционально] docxcompose: титул + задание + тело ├─ document.save() ├─ [если word] word_fix.fix_continuations() # COM: реальные разрывы страниц └─ [если --check-pages] page_fill_check # эвристика полупустых страниц ``` Ключевые типы: - `ConvertRequest` / `ConvertResult` — контракт CLI↔GUI (`md2gost/pipeline.py`). - `DocProfile` — правила типа работы (`md2gost/profiles.py`). - `StyleConfig` — поля страницы + стили абзацев (`md2gost/style_config.py`). - `Renderable` — элемент, который умеет себя нарисовать в DOCX с учётом высоты страницы. --- ## 5. Что уже умеет пользователь (функции продукта) ### 5.1. Типы документов (`--type`) | Тип | Стили | Нумерация объектов | Источники | Структура | |-----|--------|-------------------|-----------|-----------| | `practice` | mirea | по разделам `1.1`, `2.1` | 5–7, ≤5 лет | Введение, разделы, заключение, список, приложения | | `coursework` | mirea | то же | 5–7, ≤5 лет | то же | | `vkr` | mirea | то же | ≥10 **в каждом** разделе списка, ссылки `[1.5]` | + приложение «Графический материал» | | `PIS_custom` | pis_custom | сквозная `1, 2, 3` | не обязательны | H1 = «Практическая работа №N. …»; H1 по центру ПРОПИСНЫМИ; H2 с абзацным отступом | | `APID_coursework` | mirea | по разделам | 7–20, ≤5 лет | обязательные главы «Теоретические…» / «Прикладные…» и пункты 2.1–2.4 | Реализация: `PROFILES` и `get_profile()` в `profiles.py`. Стили пресетов: `preset_mirea()`, `preset_pis_custom()`. ### 5.2. CLI (все флаги) Точка входа: `md2gost/__main__.py` → `build_parser()`, `request_from_args()`, `main()`. | Флаг | По умолчанию | Что делает | |------|----------------|------------| | `filename` | нет → GUI | `.md` или `.docx` с `--check-pages` | | `--gui` | | открыть окно (можно сразу передать `.md`) | | `-o` / `--output` | рядом с md, то же имя | выходной DOCX | | `-t` / `--template` | `md2gost/Template.docx` | шаблон Word | | `--type` | `practice` | профиль документа | | `--heading-numbering` | `manual` | `manual` — цифры из md, автонумерация Word выкл.; `auto` — нумерует Word, цифры в начале заголовка снимаются | | `--toc` | `native` | `native` — поле Word `TOC`; `manual` — сборка по LayoutTracker | | `--table-continuation` | `word` | `word` / `off` / `soft` / `legacy` / `caption` | | `--listing-continuation` | `word` | то же для листингов | | `--table-repeat-header` | выкл. | шапка на фрагментах после word-split | | `--emdash-to-hyphen` | выкл. | «—» → «-» | | `--hr-pagebreak` | выкл. | `---` / `***` / `___` → разрыв страницы | | `--title` / `--assignment` | | DOCX титула и бланка задания (склейка через docxcompose) | | `--auto-title` / `--no-auto-title` | | автотитул из yaml/` ```title ` (по умолчанию выкл.) | | `--student` / `--group` | | ФИО и группа для автотитула (иначе `md2gost.user.json`) | | `--doc-author-from` / `--doc-author` | `os` / профиль | автор в свойствах DOCX: `os` (имя ОС), `student`, `custom` | | `--doc-title` / `--doc-subject` / `--doc-keywords` / `--doc-comments` / `--doc-category` / `--doc-last-modified-by` | см. профиль | остальные поля File → сведения; пустые comments — без штампа md2gost | | `--check` / `--check-only` / `--strict` | | проверка ТЗ; `--strict` → код выхода 1 при ошибках | | `--check-pages` | | полупустые страницы через Word COM (эвристика, не влияет на `--strict`) | | `--syntax-highlighting` | | Pygments в листингах | | `--plantuml-jar` / `--kroki-url` | | локальный рендер диаграмм | | `--diagram-fallback` | `remote` | `remote` / `local` / `off` | | `--diagram-format` | `png` | `png` или `svg` (svgBlip + PNG-запасной) | | `--diagram-scale` | `2.0` | качество PNG PlantUML (размер на странице как при 1) | | `--schemes` | авто | путь к `md2gost.schemes.json` | | `--styles` | авто | оверлей `md2gost.styles.json` | | `--debug` | | отладочная сетка в документе + открыть файл | Занятый выходной файл: `timestamped_output_path()` пишет `имя_ГГГГ-ММ-ДД-ЧЧ-ММ.docx`. Windowed exe: `_argv_needs_console()` + `_enable_windows_console()` — консоль появляется только для CLI/`--help`, не для GUI. ### 5.3. GUI (Tkinter) Модуль `md2gost/gui.py`, класс `Md2GostApp`. Entry: `md2gost-gui` / `python -m md2gost` без файла / `--gui`. Уже есть: - зона Drop: перетаскивание `.md` (tkinterdnd2, иначе Win32 `WM_DROPFILES`, иначе клик → диалог); - основные параметры: тип, нумерация заголовков, TOC, continuation таблиц/листингов, тире, `---` → разрыв, проверки ТЗ, вёрстка, открыть после сборки; - **Настройки → Файлы**: шаблон, титул, задание, стили JSON, выходной путь; - **Настройки → Студент…**: ФИО и группа (первый запуск); - **Настройки → Метаданные…**: свойства DOCX (автор, название, тема, теги, примечание) в `md2gost.user.json`; - **Настройки → Диаграммы**: jar, Kroki, fallback, формат, масштаб, статус движка, скачать PlantUML, сброс кэша includes; - **Шаблоны UML**: CRUD схем (`md2gost.schemes.json`) — добавить / дублировать / удалить / сохранить / открыть JSON; - **Справка**: Инструкция, Документация (вшитые `docs/*.md`), Схемы, Промпт для ИИ (каталог `prompts/` + кнопки схем); - конвертация в фоне (`threading`), лог в окне, тултипы, меню «Дебаг» на одну следующую сборку; - если выходной DOCX занят — timestamp-имя, как в CLI. Конвертация не блокирует окно: `_convert()` → поток → `_on_done()`. ### 5.4. Диалект Markdown Реализовано в `extended_markdown/` (расширение Marko + GFM) и `RenderableFactory`. | Элемент | Синтаксис | Поведение | |---------|-----------|-----------| | Спецраздел без номера | `# *ВВЕДЕНИЕ` | ПРОПИСНЫЕ, без автономера раздела | | Содержание | `# *СОДЕРЖАНИЕ` + `[TOC]` | native поле Word или ручная сборка | | Рисунок-файл | `![…](file.png "%id Подпись")` | нумерация + `@Рисунок:id` | | Таблица | `%id Подпись` перед таблицей | подпись «Таблица N — …» | | Merge ячеек | `^` rowspan, `>` colspan | OOXML `vMerge` / `gridSpan`; через разрыв страницы merge не переносится | | Листинг | `%id` + code fence | Courier New, опционально Pygments | | Диаграмма | `%id` + ` ```uml ` / `uml-c4` / `mermaid` / `idef0` / `dfd` | Рисунок; флаги `+listing`, `+landscape` | | Формула | `%eq1` + `$$…$$` + `@Формула:eq1` | номер только если есть ссылка | | Инлайн-формула | `$…$` | OMML в абзаце | | Ссылка на объект | `@Рисунок:id`, `@Таблица:id`, `@Листинг:id`, `@Формула:id` | подстановка номера | | Источник | `[1]` в тексте, `[1]: …` в списке | ВКР: `[1.5]`, цитата `[2.18, c. 21-25]` | | Разрыв страницы | `---` + `--hr-pagebreak` | иначе HR игнорируется | | Жирный / курсив / зачёркивание / ссылки / списки | обычный MD | поддерживается | Автоправки текста (`preprocess_markdown`): - `"..."` → «…» (эвристика, не внутри `%…`); - `слово - слово` → `слово — слово` (если не `--emdash-to-hyphen`); - внутри оград UML/Mermaid/схем **не** трогает кавычки и тире; - в списке источников каждый `[n]:` выносится в отдельный абзац (`separate_biblio_lines`). ### 5.5. Схемы и диаграммы Встроенные id (`md2gost/diagrams/schemes.json`): `c4`, `c4context`, `c4component`, `usecase`. Слои загрузки (позже побеждает): встроенный шаблон → `md2gost.schemes.json` рядом с приложением (создаётся при первом запуске, не перезаписывается) → рядом с `.md` → `--schemes`. Рендер UML: 1. Java + `plantuml.jar` (вшитый / `%LOCALAPPDATA%\md2gost\` / `--plantuml-jar`); 2. локальный Kroki (`KROKI_URL` / `--kroki-url`); 3. `https://kroki.io` при `--diagram-fallback remote`. Mermaid — локально (браузер / QuickJS) или Kroki. **IDEF0** — оградка ` ```idef0 `, локальный Pillow (рамка NIST). **DFD** — оградка ` ```dfd `, пакет [data-flow-diagram](https://github.com/pbauermeister/dfd) → вшитый/кэш/PATH Graphviz (`scripts/fetch_graphviz.py`, GUI «Скачать Graphviz») или Kroki. Кэш картинок: `{каталог_md}/.md2gost-cache/`. Кэш `!include` URL: `md2gost.include-cache.json` + `include-cache/`. Альбомная страница: флаг `+landscape` у подписи — отдельная секция A4 landscape с вертикальным центрированием, затем снова книжная. Один section break (без пустой книжной страницы перед альбомом). ### 5.6. Кастомные стили JSON Файл `md2gost.styles.json` (рядом с `.md` и/или `--styles`). Deep-merge поверх пресета типа. Неизвестный ключ или имя стиля — ошибка (`StyleConfigError`). Можно менять поля `page` (мм) и поля стилей абзацев: шрифт, кегль, жирный/курсив/прописные, выравнивание, отступы, интервал 1.0/1.5, `page_break_before`, `keep_with_next`, `widow_control`. Не в JSON: табы оглавления (считаются от ширины полосы), отступы списков, цвет (всегда чёрный), формулы из шаблона. ### 5.7. Проверка ТЗ (`--check`) Модуль `md2gost/checker/__init__.py`. Возвращает `Issue(id, severity, message, line)`. Уже проверяется: - обязательные разделы по профилю (СОДЕРЖАНИЕ, ВВЕДЕНИЕ, ЗАКЛЮЧЕНИЕ, список; для ПИС — практические работы; для ВКР — «Графический материал»; для АПИД — 6 обязательных заголовков); - `[TOC]`; - спецразделы должны быть `# *…`, лучше ПРОПИСНЫМИ; - запрет «рис.», «табл.», сносок `[^1]`, графы «№ п/п»; - ссылки `[n]` во введении/заключении запрещены; - число и возраст источников; для ВКР — по разделам списка; порядок первого упоминания; - висячие / неиспользованные метки `%id` / `@Тип:id`; - запрещённые буквы приложений (Ё З Й О Ч Ь Ы Ъ); - перечень приложений после `# *ПРИЛОЖЕНИЯ`, если приложений ≥ 2; - маркеры merge `^`/`>` в шапке и `>` в первом столбце; - подсказка про «Продолжение…», если continuation = `off`/`soft`. `--strict` падает только на `severity == "error"`. `--check-pages` — отдельная эвристика, в strict не входит. ### 5.8. Продолжение таблиц и листингов DOCX сам не умеет писать «Продолжение Таблицы N» только со 2-й страницы. | Режим | Поведение | |--------|-----------| | **`word`** (по умолчанию) | После save Word COM режет по реальной пагинации, вставляет подпись | | **`off` / `soft`** | Одна таблица/листинг, пагинацию делает Word, без автоподписи | | **`legacy`** | Резка по оценке высоты LayoutTracker + `page_break_before` (могут быть дыры) | | **`caption`** | То же + явный PageBreak | Оценка высоты ≠ вёрстка Word — поэтому `legacy`/`caption` помечены как неточные. ### 5.9. Титул, задание, колонтитулы `--title` / `--assignment`: пустая оболочка из шаблона + docxcompose (титул, разрыв, задание, разрыв, тело). На секциях титула/задания колонтитул без номера страницы; дальше — сквозная нумерация, поле `PAGE`, TNR 12 по центру. После TOC начинается секция тела с номерами. Если в документе нет TOC — номер ставится на единственную секцию. **Автотитул** (по умолчанию **выкл.**; CLI `--auto-title` / галочка в GUI; явный `--title` отключает генератор): см. [`docs/title.md`](docs/title.md). Кратко: `md2gost/title_page.py` заполняет bundled `TitleTemplate.docx` из `info_conv.yaml` и/или блока ` ```title `, ФИО/группа — `md2gost.user.json` или `--student`/`--group`. GUI: первый запуск и **Настройки → Студент…**. **Свойства DOCX** (после склейки титула, перед save): `doc_metadata.apply_document_metadata`. По умолчанию автор = `getuser()`, примечание «Создано при помощи md2gost (ТЗ МИРЭА)», created/modified = сейчас, revision = 1. GUI **Настройки → Метаданные…** / флаги `--doc-*`. Профиль — блок `metadata` в `md2gost.user.json`. ### 5.10. Приложения - Буквы: А Б В Г Д Е Ж И К … (без Ё З Й О Ч Ь Ы Ъ) — `APPENDIX_LETTERS` в `numberer.py`. - `## Приложение А Название` оформляется как приложение. - Если после `# *ПРИЛОЖЕНИЯ` нет перечня, а приложений несколько — Renderer **сам вставляет** список «Приложение А — …». Если автор уже написал перечень — не дублирует. ### 5.11. Промпты для ИИ | Файл | Назначение | |------|------------| | `prompts/generate-md.md` | диалект md2gost vs обычный MD | | `prompts/generate-mirea-report.md` | полный отчёт ГОСТ / МИРЭА | | `prompts/generate-pis-custom-report.md` | итоговый отчёт ПИС | | `prompts/emulate-student.md` | голос: человечный текст, не отчёт ИИ | В GUI: выбор промпта + чекбоксы схем → в конец дописываются `ai-prompt` и макросы из `md2gost.schemes.json` (`compose_prompt()`). ### 5.12. Сборка и поставка - `pyproject.toml`: hatchling, пакеты `md2gost`, `md2latex`, `md2fodt`; в wheel вшиваются Template.docx, mml2omml, diagrams, latex/mirea, prompts, docs. - `md2gost.spec` / `md2gost.fast.spec` — PyInstaller (вшивают `plantuml.jar` и при наличии `vendor/graphviz`). - `scripts/fetch_plantuml.py` — скачать jar. - `scripts/fetch_graphviz.py` — скачать portable Graphviz в `md2gost/vendor/graphviz` (для DFD в exe). - `scripts/md2gost_exe.py` — обёртка exe. - `scripts/pyi_rth_mplbackend.py` — runtime hook matplotlib для PyInstaller. - `scripts/check_page_fill.bas` — макрос Word для той же эвристики вёрстки. - `scripts/md2pdf.ps1` / `md2pdf.sh` — обёртки LaTeX→PDF. - CI: `.github/workflows/pytest.yml` (Python 3.11, flake8, pytest); `example-generator.yml`. --- ## 6. Карта модулей md2gost и функции кода Ниже — публичные и важные внутренние функции **уже реализованные**. Приватные `_foo` указаны, если без них не понять модуль. ### 6.1. Точки входа и пайплайн **`md2gost/__init__.py`** - `package_dir()` — каталог пакета (и `_MEIPASS` в frozen exe). **`md2gost/__main__.py`** - `build_parser()` — argparse. - `request_from_args(args)` → `ConvertRequest`. - `_argv_needs_console(argv)`, `_enable_windows_console()`. - `main()`. **`md2gost/pipeline.py`** - `ConvertRequest`, `ConvertResult`. - `default_output_path(filename)`, `timestamped_output_path(path)`, `default_template_path()`. - `open_document(path)` — macOS `open` / Windows `startfile` / `xdg-open`. - `_fix_front_matter_after_compose(...)` — сброс PAGE на титуле/задании, сквозная нумерация. - `convert(req, log=None)` — весь конвейер, ошибки в `ConvertResult`, не пробрасывает исключение наружу. Перед save — `apply_document_metadata`. - `should_launch_gui(filename, gui_flag)`. - `_CallbackLogHandler` — логи md2gost в GUI/CLI. **`md2gost/doc_metadata.py`** - `DocumentMetadata`, `DEFAULT_DOC_COMMENTS`, `AUTHOR_SOURCES`. - `os_user()`, `clip_core()` (лимит 255 символов python-docx). - `resolve_document_metadata(...)` — профиль + CLI/request. - `apply_document_metadata(document, meta)` — core properties + даты + revision=1. **`md2gost/user_profile.py`** - `UserProfile` (student, group, metadata), `load_user_profile` / `save_user_profile` → `md2gost.user.json`. **`md2gost/converter.py`** - класс `Converter`: читает md, применяет стили, парсит, нумерует, рендерит. - `convert()`, свойства `document`, `style_config`, `raw_markdown`, `doc_type`, `heading_numbering`. ### 6.2. Профили и стили **`md2gost/profiles.py`** - константы: `DOC_TYPES`, `HEADING_NUMBERING_MODES`, `TOC_MODES`, `TABLE_CONTINUATION_MODES`, `LISTING_CONTINUATION_MODES`, `NUMBERING_SCOPES`, `STYLE_PRESETS`. - `DocProfile` — поля min/max источников, sectional_biblio, require_graphic_appendix, style_preset, numbering_scope, флаги структуры, `require_apid_kr_structure`. - `get_profile(doc_type)`. - `fix_russian_quotes`, `fix_dashes`, `replace_emdash_with_hyphen`. - `set_emdash_to_hyphen`, `emdash_to_hyphen_enabled`, `dash_separator`. - `preprocess_markdown`, `separate_biblio_lines`. - `find_formula_refs` — `@Формула:` / `@Formula:`. - `current_year()`. **`md2gost/style_config.py`** - `StyleConfigError`. - `PageSpec.merge/to_dict/require_complete`. - `ParagraphStyleSpec.merge/to_dict`. - `StyleConfig.merge/to_dict`. - `preset_mirea()`, `preset_pis_custom()`, `get_preset(name)`. - `style_config_from_dict`, `load_styles_file`, `resolve_style_config` (пресет ← рядом с md ← `--styles`). **`md2gost/styles.py`** - `apply_style_config(document, config)` — поля, секции, табы TOC, стили абзацев. - `apply_mirea_styles`, `apply_pis_custom_styles`. - `apply_document_styles(...)` — пресет + оверлей, возвращает итоговый `StyleConfig`. - Внутри: `_set_run_font` (блокирует тему Word: Calibri/синий), `_ensure_style`, `_fix_toc_tab_stops`. **`md2gost/page_geometry.py`** - глобальные поля `MARGIN_*`, `MARGIN_PRESETS`, `apply_margin_preset`. - `is_landscape_section`, `apply_section_geometry`, `content_size`. - `apply_centered_page_footer`, `clear_section_footer`, `ensure_continuous_page_numbers`. ### 6.3. Разбор Markdown **`md2gost/extended_markdown/`** - `__init__.py` — Marko + GFM + Extension: Equation, Reference, Caption, Table, TOC, Heading, InlineEquation, Image. - `heading.py` — `# *` → ненумерованный. - `caption.py` — строка `%id текст +listing +landscape`. - `table.py` — GFM-таблица + `^`/`>` + `_resolve_merge_restarts`. - `image.py` — `%id` в title картинки. - `equation.py` — блочная `$$`. - `inline_formula.py` — `$…$`. - `reference.py` — `@Тип:id`. - `toc.py` — `[TOC]`. **`md2gost/parser_.py`** - `Parser.parse()` — пропускает пустые строки; копит `CaptionInfo`; HR без флага игнорирует; иначе `factory.create`. **`md2gost/renderable_factory.py`** - `RenderableFactory.create` (singledispatch): Paragraph, Heading, FencedCode/CodeBlock → Listing или DiagramFigure, Equation, List, Table, TOC, ThematicBreak → PageBreak. - `_create_runs` — жирный/курсив/зачёркивание, код, картинки, инлайн-формулы, `@ссылки`, гиперссылки. ### 6.4. Нумерация и ссылки **`md2gost/numberer.py`** - `Numberer(mode="section"|"continuous")`: `enter_section`, `enter_appendix`, `next_number`, `resolve`, `register_label`. - Режим section: `1.1` / `Б.1`, счётчики сбрасываются на разделе/приложении. - Режим continuous: `1, 2, 3` на весь документ (ПИС). **`md2gost/label_pass.py`** - `LabelRegistry.put/get/get_display` (алиасы Рисунок/Figure/Таблица/…). - `assign_numbers(renderables, numbered_equations, numbering_scope)`. - `resolve_pending_in_renderables`, `set_active_registry`, `resolve_reference`. Формулы нумеруются **только** если на них есть `@Формула:…` в исходнике. ### 6.5. Рендер в DOCX **`md2gost/renderer.py` — класс `Renderer`** - `process(renderables)` — основной цикл. - Секции: фронт без номеров → после TOC тело с PAGE; `_enter_landscape` / `_exit_landscape`. - `_ensure_appendix_index` — автоперечень приложений. - Нумерация объектов через `Numberer` (если не `skip_numbering` — в Converter нумерация уже в label_pass). - Спецзаголовки: СОДЕРЖАНИЕ / СПИСОК — по центру; Введение / Заключение / ПРИЛОЖЕНИЯ — слева как H1. **`md2gost/layout_tracker.py`** - `LayoutState` — текущая/оставшаяся высота, номер страницы. - `LayoutTracker` — `add_height`, `can_fit_to_page`, `new_page`, `set_page_size` (книга ↔ альбом). **`md2gost/renderable/`** | Класс | Файл | Роль | |--------|------|------| | `Renderable` | `renderable.py` | абстрактный `render()` | | `Paragraph` / `Link` | `paragraph.py` | абзац, runs, картинки, ссылки, инлайн-формулы | | `Heading` | `heading.py` | уровни 1–9, manual/auto, снятие Word numbering, strip ведущих цифр | | `Table` | `table.py` | сетка, merge, continuation, `+landscape` | | `Listing` | `listing.py` | код, Pygments (`DocxParagraphPygmentsFormatter`), continuation | | `Image` | `image.py` | файл-рисунок + подпись | | `DiagramFigure` | `diagram.py` | рендер схемы + опциональный Listing исходника | | `Equation` | `equation.py` | блочная формула OMML + номер справа | | `Caption` / `CaptionInfo` | `caption.py` | «Рисунок 1.1 — …» | | `List` | `list.py` | маркированные/нумерованные, вложенность | | `ToC` | `toc.py` | native field `TOC \o "1-3" \h \z \u` или ручные строки с табами | | `PageBreak` | `page_break.py` | явный разрыв | | `RequiresNumbering` | `requires_numbering.py` | интерфейс нумеруемых объектов | | `ParagraphSizer` / шрифты | `paragraph_sizer.py`, `find_font.py` | оценка высоты абзаца (FreeType) | **`md2gost/docx_elements.py`** - `create_table`, `create_table_row`, `create_table_cell`, `apply_cell_merge`, `set_table_box_borders`, фиксация ширины в twips. **`md2gost/docx_svg.py`** - `attach_svg_blip(run, inline_shape, svg_path)` — вектор + PNG fallback. **`md2gost/latex_math.py`** - `latex_to_omml(latex)` — latex2mathml + XSLT `mml2omml`. - `inline_omml(omml)` — дроби в линейный вид для инлайна. **`md2gost/toc_processor.py`** - `TocProcessor.process` — native: `updateFields` при открытии Word; manual: страницы из `Heading.rendered_page` (СОДЕРЖАНИЕ в оглавление не попадает). **`md2gost/debugger.py`** - плавающая сетка страниц в документе (`--debug`): `Debugger`, `add_float_picture`, `new_pic_anchor`. **`md2gost/util.py`** - `create_element` — низкоуровневый OOXML. ### 6.6. Библиография **`md2gost/bibliography.py`** - `BiblioEntry`, `extract_year`, `parse_biblio_block`, `find_citations`. - `Bibliography(...)` — ленивая обёртка над renderable (чтобы checker не тянул docx). **`md2gost/biblio_processor.py`** - `entries_from_text` — несколько `[n]:` внутри одного абзаца (Marko склеивает строки). - `extract_bibliography_from_markdown` — плоский список или секции для ВКР. - `fold_bibliography(renderables, parent, raw_markdown)` — заменяет абзацы списка на `Bibliography`. **`md2gost/bibliography_renderable.py`** — отрисовка пунктов списка стилем Bibliography. ### 6.7. Диаграммы **`md2gost/diagram_schemes.py`** - `DiagramScheme` (id, title, docs, ai-prompt, includes, prefix/postfix, theme). - `bundled_schemes_path`, `user_schemes_path`, `ensure_user_schemes`. - `load_schemes_from_path`, `save_schemes`, `load_merged_schemes`. - `scheme_id_from_lang`, `is_diagram_lang`, `get_scheme`, `get_schemes`, `reload_schemes`, `configure_schemes`. - `apply_scheme`, `prepare_with_schemes`. **`md2gost/diagram_includes.py`** - кэш HTTP `!include`: `resolve_url`, `resolve_include_ref`, `rewrite_http_includes_in_source`, `reset_include_cache`, `cache_entry_count`. **`md2gost/diagram_renderer.py`** - `configure_diagrams(...)`, `DiagramConfig`, `DiagramRenderResult`. - `prepare_source`, `render_diagram`. - `resolve_plantuml_jar`, `fetch_plantuml_jar`, `iter_plantuml_candidates`, `diagram_engine_status`. - рендер jar / Kroki / пара png+svg; масштаб `scale` в исходник PlantUML. - локальные типы `LOCAL_ONLY_TYPES` (`idef0`, `dfd`): Pillow, без jar/Kroki. **`md2gost/idef0.py`** — DSL IDEF0 + Pillow/SVG. **`md2gost/dfd.py`** — обёртка [pbauermeister/dfd](https://github.com/pbauermeister/dfd): DSL → DOT → vendor/system Graphviz / Kroki (`write_dfd_outputs`, `fetch_graphviz`). **`md2gost/diagrams/`** — `schemes.json`, C4 `*.puml`. ### 6.8. Word COM и вёрстка **`md2gost/word_fix.py`** - `parse_caption_text`, `find_page_break_row`, `continuation_label`, `caption_style_name`. - `fix_continuations(path, tables, listings, repeat_header)` → `FixResult`. - Внутри: до 5 проходов `Repaginate` + `Split`, рамки листингов, опциональный повтор шапки. **`md2gost/page_fill_check.py`** - `PageMetric`, `PageFillIssue`. - `evaluate_page_fill(pages)` — чистая эвристика (порог пустого низа 40%, пропускает альбом, последнюю страницу, фронт, конец раздела, «в основном рисунок/таблица»). - `check_docx_page_fill(path)`, `format_page_fill_report`. ### 6.9. Checker (функции проверок) `md2gost/checker/__init__.py`: - `check_structure`, `check_apid_kr_structure`, `check_pis_headings`, `check_special_headings`. - `check_forbidden_abbreviations`, `check_citations_in_intro_conclusion`. - `check_bibliography`, `check_object_refs`, `check_appendices`. - `check_continuation_hints`, `check_table_merge`. - `check_markdown(...)` — оркестратор. - `format_report(issues)`. ### 6.10. GUI, DnD, справка **`md2gost/gui.py`** - `_make_root`, `_combo_values/_combo_key/_display`, `_Tooltip`, `_tip`. - `Md2GostApp`: меню, окна файлов/студента/метаданных/диаграмм/схем/справки, браузер docs, сборка промпта, DnD, `_collect()` → `ConvertRequest`, `_convert`. - `run_gui(initial)`, `main()`. **`md2gost/dnd.py`** - `parse_tkdnd_files`, `normalize_drop_paths`, `first_markdown`, `enable_file_drop`. - Win32: `_WinDropHook`, `_Win32DropApi`, `_query_drop_files`. **`md2gost/help_content.py`** - константы `USAGE_HELP`, `SCHEMES_HELP`. - `prompt_search_dirs`, `load_prompt_catalog`, `scheme_prompt_block`, `compose_prompt`. - `docs_search_dirs`, `load_docs_catalog`. --- ## 7. md2fodt — что уже есть Пакет `md2fodt/`. | Файл | Функции | |------|---------| | `__main__.py` | `main()` — CLI: файл, `-o`, `--emdash-to-hyphen` | | `converter.py` | `convert_md_to_fodt(md, output, emdash_to_hyphen)` | | `emitter.py` | `emit_body`, `emit_fodt`; эмиттеры heading/paragraph/image/table/code/list/equation; merge `^`/`>` | | `styles.py` | `styles_xml()`, `automatic_styles_xml()` — TNR 14, поля ГОСТ | | `escape.py` | `escape_text`, `xml_id` | Картинки встраиваются base64. Нет диаграмм PlantUML и нет «Продолжение таблицы». --- ## 8. md2latex — что уже есть Пакет `md2latex/` + шаблон `latex/mirea/` (вендор [mirea-ninja/Latex-Template-for-Report-Diploma-Thesis](https://github.com/mirea-ninja/Latex-Template-for-Report-Diploma-Thesis)). | Файл | Функции | |------|---------| | `__main__.py` | `main()`, `_run_xelatex` (latexmk или 2 прохода xelatex) | | `converter.py` | `package_template_dir()`, `convert_md_to_latex_project(md, out, titlepage)` — копирует шаблон, пишет `content.tex` | | `emitter.py` | `emit_document`; `_emit_longtable` с `\endfirsthead` / `\endhead` и «Продолжение таблицы N» | | `escape.py` | `escape_text`, `escape_verbatim_for_listing`, `latex_label` | Флаги: `-o` каталог, `--titlepage` PDF титула, `--pdf`, `--xelatex-passes`. --- ## 8.1. word2md — импорт DOCX Пакет `word2md/`. Эвристика: стили md2gost, иначе ГОСТ-текст подписей/заголовков. | Файл | Роль | |------|------| | `__main__.py` | CLI: `.docx`, `-o`, `--media-dir`, `--keep-toc-pages`, `--pagebreaks` | | `pipeline.py` | `ImportRequest` / `ImportResult` / `convert_docx()` | | `walker.py` | обход body, склейка Code/списков, `postprocess_blocks` (продолжения) | | `classify.py` | Heading / Caption / Code / библио / спецразделы | | `captions.py` | `Рисунок` / `Таблица` / `Листинг` + `parse_caption_text` из md2gost | | `tables.py` | merge → `^`/`>`, детект формульной таблицы | | `omml.py` | OMML → читаемая формула | | `media.py` | выгрузка `word/media` | | `emit.py` | IR → диалект md2gost | | `refs.py` | `Рисунок 1.1` → `@Рисунок:fig1_1` | Точки входа также: `python -m md2gost report.docx`, GUI «Импорт DOCX→MD». --- ## 9. Тесты — что покрыто Каталог `tests/`, CI гоняет `pytest`. | Файл | Что проверяет | |------|----------------| | `test_pipeline.py` | GUI/CLI развилка, пути, DnD, argparse, HR→pagebreak, промпты, docs catalog, listing continuation | | `test_mirea_tz.py` | Numberer, checker (coursework/PIS/ВКР/АПИД), препроцесс, TOC, заголовки, приложения, библио, page-fill эвристика, стили H1 | | `test_style_config.py` | merge оверлея, неизвестные ключи, CLI побеждает файл рядом с md, применение к Document | | `test_table_merge.py` | `^`/`>`, OOXML merge, checker merge, режимы continuation | | `test_word_fix.py` | разбор подписей, индекс разрыва, COM smoke (если нет Word — мягко) | | `test_landscape.py` | геометрия альбома, секции, картинки/таблицы/листинги, один section break | | `test_layout_tracker.py` | страницы и остаток высоты | | `test_paragraph.py` / `test_paragraph_sizer.py` | абзацы и измерение шрифта | | `test_diagram_renderer.py` | схемы, кэш, mermaid, svg, jar, `+listing`/`+landscape` | | `test_idef0.py` | DSL IDEF0, PNG/SVG, интеграция `render_diagram` | | `test_dfd.py` | DFD data-flow-diagram, mock Graphviz/Kroki, интеграция `render_diagram` | | `test_md2fodt.py` | escape, каркас FODT, запись файла | | `test_md2latex.py` | longtable continuation, генерация проекта | | `test_word2md.py` | подписи, спецзаголовки, @ссылки, продолжения таблиц, DOCX→MD, round-trip | | `extended_mardown/formula.py` | формулы (unittest) | Нет полного e2e «открыть Word и сравнить каждую страницу» в Linux CI (шрифты ставятся, Word COM — нет). --- ## 10. Документация и примеры Пользовательские страницы (те же вшиты в exe, GUI: Справка → Документация): | Файл | Содержание | |------|------------| | `ReadMe.md` | краткий старт репозитория | | `docs/README.md` | оглавление docs | | `docs/quickstart.md` | установка, exe, типы | | `docs/markdown.md` | диалект | | `docs/schemes.md` | UML/Mermaid, JSON схем | | `docs/types.md` | профили работ | | `docs/cli-gui.md` | флаги ↔ GUI | | `docs/styles.md` | JSON стилей | | `docs/prompts.md` | ИИ-промпты | | `docs/word2md.md` | импорт DOCX → Markdown | | `md2gost/README.md` | справка пакета (подробнее про continuation и диаграммы) | | `prompts/README.md` | как копировать промпты | | `examples/example.md`, `examples/pis_custom.md` | образцы | | `examples/md2gost.styles.json` | пример оверлея стилей | --- ## 11. Зависимости Обязательные (`pyproject.toml`): python-docx, marko, docxcompose, freetype-py, pillow, requests, latex2mathml, pygments, lxml. Опционально: pywin32 (Word COM), matplotlib (сборка exe / отладка), tkinterdnd2 (удобный DnD в GUI). Внешние рантаймы: Java + plantuml.jar **или** Kroki; Graphviz (вшитый/кэш/PATH) для DFD; для PDF — XeLaTeX / latexmk и шрифт Times New Roman. --- ## 12. Что в репозитории, но не продукт Черновики и чужой код рядом с пакетами. Это **не** часть `pip install` / exe: - корень: `main.py`, `main12.py`, `mm2.py`…`mm5.py`, `asd.py`, `parser.py`, `font.py`, `_audit_tmp.py`, `tmp_listing_word.md`, `todo.txt`; - `ad/` — черновые отчёты; - `_paco_extract/` — выгрузки методичек ПАЦО; - `Other_Code/` — справка OOXML, docx-js, скрипты pack/unpack/validate (не импортируется md2gost); - артефакты сборки `build-fast/`, кэши диаграмм. `todo.txt` сейчас: «оценки с текстом через сам Word, а не предугадывание» — частично закрыто режимом `word`. --- ## 13. Чего нет / ограничения (честно) - DFD: пакет `data-flow-diagram` в зависимостях; картинка — вшитый/кэш/PATH Graphviz или Kroki; балансировка уровней не проверяется. - FODT и LaTeX не догоняют md2gost по GUI, checker, схемам, профилям PIS/АПИД, Word COM. - «Продолжение таблицы» в чистом DOCX без Word невозможно точно (нет longtable). Без Word — `off` или неточный `legacy`/`caption`. - `--check-pages` даёт ложные срабатывания; это эвристика. - Merge ячеек не живёт через границу разрезанной таблицы. - Цвет текста в стилях не настраивается (всегда чёрный). - Профиль `paco_custom` упомянут в комментарии `page_geometry`, отдельного типа в `DOC_TYPES` нет. - Нумерация заголовков H4+ в стилях JSON не описана (в Word уровни 1–9 у Heading есть). --- ## 14. Типичные сценарии «уже работает» 1. **Практика / курсовая МИРЭА:** `# *ВВЕДЕНИЕ` … `# 1 …` … список `[1]:` → `--type practice|coursework --check --strict`. 2. **ВКР:** раздельный список, ссылки `[1.5]`, приложение «Графический материал». 3. **ПИС:** `# Практическая работа №1. …` → `--type PIS_custom`, сквозные Рисунок 1, 2, 3. 4. **АПИД:** обязательные 2 главы и 2.1–2.4, источники 7–20. 5. **UML в отчёте:** `%id Подпись` + ` ```uml-c4 ` — PNG/SVG в Word, опционально `+listing` и `+landscape`. 6. **Широкая таблица:** `%id … +landscape`. 7. **Длинная таблица на Windows:** режим `word` → COM режет и пишет «Продолжение Таблицы N». 8. **Свой вуз/кафедра:** `md2gost.styles.json` меняет поля и H1 без правки кода. 9. **Своя схема:** GUI «Шаблоны UML» или JSON с `includes`/`prefix`/`ai-prompt`. 10. **Черновик через ИИ:** промпт из GUI + схемы → `.md` → конвертер. 11. **Только проверить готовый DOCX:** `python -m md2gost report.docx --check-pages`. 12. **Без Word:** `python -m md2fodt` или `python -m md2latex --pdf`. --- ## 15. Поток данных одним абзацем Пользователь кладёт `.md` (и опционально титул/задание/JSON стилей/схем). `convert()` читает текст, при необходимости гоняет checker, препроцессит кавычки/тире, парсит Marko-расширением в дерево, фабрика делает Renderable, библиография сворачивается в особые абзацы, объектам раздаются номера по профилю, `@ссылки` заменяются на «Рисунок 2.1», Renderer кладёт OOXML в очищенный Template.docx с оценкой высоты страницы, TocProcessor дописывает содержание, pipeline склеивает титул, сохраняет DOCX, при режиме `word` открывает файл в Word и режет таблицы/листинги по настоящей пагинации. GUI делает ровно то же, только параметры собирает из формы. --- ## 16. Где править, если добавлять функцию | Хочешь | Куда | |--------|------| | Новый тип работы | `profiles.PROFILES` + checker + стили пресета | | Новое поле CLI/GUI | `__main__.build_parser`, `ConvertRequest`, `gui._collect/_apply_request` | | Новый элемент Markdown | `extended_markdown/` + `RenderableFactory` + класс в `renderable/` | | Новая проверка ТЗ | `checker/__init__.py` → вызов из `check_markdown` | | Новая UML-схема «из коробки» | `md2gost/diagrams/schemes.json` (+ `.puml` при необходимости) | | Новое поле стиля | `style_config.STYLE_FIELD_KEYS` + `ParagraphStyleSpec` + `_apply_paragraph_spec` | | Паритет FODT/LaTeX | `md2fodt/emitter.py` / `md2latex/emitter.py` | --- *Файл сгенерирован по состоянию исходников репозитория (пакет 0.1.0). Пользовательские howto — в `docs/`. Этот файл — инвентарь возможностей и кода.*