hot-fix Build.bat 0.4.5
Python application / build (push) Has been cancelled

This commit is contained in:
Igor20264
2026-09-06 11:13:41 +03:00
parent 818a044aa1
commit ac0aa33399
5 changed files with 772 additions and 76 deletions
+683
View File
@@ -0,0 +1,683 @@
# 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 / BPMN / 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 через шаблон МИРЭА |
Общий диалект разметки: спецразделы `# *ВВЕДЕНИЕ`, метки `%id`, ссылки `@Рисунок:id`, таблицы с `^`/`>`, формулы `$$`, библиография `[n]: …`.
Полнота реализации **не одинаковая**:
- **md2gost** — полный конвейер (стили, профили, диаграммы, checker, GUI, Word COM).
- **md2fodt** — v1: текст, заголовки, списки, таблицы с merge, картинки, листинги, простые ссылки, библиография. Нет PlantUML, нет «Продолжение таблицы», нет полного паритета PIS/АПИД.
- **md2latex** — тот же диалект → `content.tex` + копия `latex/mirea/`. Таблицы идут в `longtable` с настоящим «Продолжение таблицы N» (это умеет LaTeX, не Word).
---
## 3. Как запустить
```bash
pip install -e .
python -m md2gost # GUI
python -m md2gost report.md -o report.docx --type coursework --check
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).
Быстрая сборка: `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 | то же | 57, ≤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) |
| `--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, выходной путь;
- **Настройки → Диаграммы**: 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` / `bpmn` / `mermaid` | Рисунок; флаги `+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`, `bpmn`.
Слои загрузки (позже побеждает): встроенный шаблон → `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 — только Kroki. **IDEF0 / DFD конвертер не рисует** — только готовый PNG.
Кэш картинок: `{каталог_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 — номер ставится на единственную секцию.
### 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` | итоговый отчёт ПИС |
В 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.
- `scripts/fetch_plantuml.py` — скачать jar.
- `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`, не пробрасывает исключение наружу.
- `should_launch_gui(filename, gui_flag)`.
- `_CallbackLogHandler` — логи md2gost в GUI/CLI.
**`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` | уровни 19, 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.
**`md2gost/diagrams/`** — `schemes.json`, `BPMN.puml`, 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`.
---
## 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` | схемы, BPMN, кэш, mermaid, svg, jar, `+listing`/`+landscape` |
| `test_md2fodt.py` | escape, каркас FODT, запись файла |
| `test_md2latex.py` | longtable continuation, генерация проекта |
| `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/BPMN, JSON схем |
| `docs/types.md` | профили работ |
| `docs/cli-gui.md` | флаги ↔ GUI |
| `docs/styles.md` | JSON стилей |
| `docs/prompts.md` | ИИ-промпты |
| `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; для 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` сейчас: «ожидаем BPMN в mermaid» и «оценки с текстом через сам Word, а не предугадывание» — второе частично закрыто режимом `word`.
---
## 13. Чего нет / ограничения (честно)
- IDEF0 и DFD конвертер не рисует.
- 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 уровни 19 у 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, источники 720.
5. **UML в отчёте:** `%id Подпись` + ` ```uml-c4 ` / ` ```bpmn ` — 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/`. Этот файл — инвентарь возможностей и кода.*
+3 -1
View File
@@ -14,7 +14,9 @@ Windows: `build-exe.bat` → `dist\md2gost.exe` (двойной клик — GUI
## Документация
Полное описание — в [`docs/`](docs/):
Полная карта проекта (что уже умеет, пайплайны, модули): [`PROJECT.md`](PROJECT.md).
Пользовательская документация — в [`docs/`](docs/):
| Раздел | Содержание |
|--------|------------|
+49 -45
View File
@@ -1,70 +1,46 @@
@echo off
setlocal EnableExtensions
chcp 65001 >nul
cd /d "%~dp0"
chcp 65001 >nul 2>&1
set "DO_PAUSE=1"
set "PYI_CLEAN="
for %%A in (%*) do (
if /i "%%~A"=="nopause" set "DO_PAUSE=0"
if /i "%%~A"=="clean" set "PYI_CLEAN=--clean"
)
if /i "%~1"=="nopause" set "DO_PAUSE=0"
if /i "%~2"=="nopause" set "DO_PAUSE=0"
if /i "%~1"=="clean" set "PYI_CLEAN=--clean"
if /i "%~2"=="clean" set "PYI_CLEAN=--clean"
echo === md2gost: быстрая сборка exe (onefile, шрифты + plantuml.jar) ===
echo === md2gost: быстрая сборка exe, onefile, шрифты и plantuml.jar ===
echo Каталог: %CD%
echo Spec: md2gost.fast.spec
echo Кэш: build-fast\ (без --clean, пока не передадите clean)
echo Кэш: build-fast\ без --clean, пока не передадите clean
echo.
where python >nul 2>&1
if errorlevel 1 (
echo Python не найден в PATH. Установите Python 3.10+ и отметьте "Add python.exe to PATH".
goto :fail
)
if errorlevel 1 goto :nopython
python -c "import sys; raise SystemExit(0 if sys.version_info >= (3, 10) else 1)"
if errorlevel 1 (
echo Нужен Python 3.10 или новее.
python --version
goto :fail
)
python -c "import sys; raise SystemExit(sys.hexversion < 0x030A0000)"
if errorlevel 1 goto :oldpython
echo [1/4] Зависимости ...
python -c "import PyInstaller, matplotlib, docx, marko, lxml, pygments, PIL, freetype, latex2mathml, requests, docxcompose" 1>nul 2>nul
if errorlevel 1 (
echo Ставлю проект + PyInstaller + matplotlib ...
python -m pip install -q -e . "pyinstaller>=6.0" "matplotlib>=3.7"
if errorlevel 1 (
echo Не удалось поставить зависимости.
goto :fail
)
) else (
echo Уже стоят, pip пропускаю.
)
if not errorlevel 1 goto :deps_ok
echo Ставлю проект + PyInstaller + matplotlib ...
python -m pip install -q -e . "pyinstaller>=6.0" "matplotlib>=3.7"
if errorlevel 1 goto :pipfail
:deps_ok
if not exist "md2gost\Template.docx" (
echo Нет md2gost\Template.docx — сборка бессмысленна.
goto :fail
)
if not exist "md2gost\Template.docx" goto :notemplate
echo [2/4] PlantUML jar (обязателен, вшивается в exe) ...
echo [2/4] PlantUML jar, обязателен, вшивается в exe ...
python scripts\fetch_plantuml.py
if not exist "md2gost\vendor\plantuml.jar" (
echo Нет md2gost\vendor\plantuml.jar — portable exe без jar не собираем.
goto :fail
)
if not exist "md2gost\vendor\plantuml.jar" goto :nojar
echo [3/4] PyInstaller onefile, кэш build-fast ...
python -m PyInstaller --noconfirm %PYI_CLEAN% --workpath build-fast --distpath dist md2gost.fast.spec
if errorlevel 1 (
echo PyInstaller завершился с ошибкой.
goto :fail
)
if errorlevel 1 goto :pyifail
if not exist "dist\md2gost.exe" (
echo dist\md2gost.exe не появился.
goto :fail
)
if not exist "dist\md2gost.exe" goto :noexe
echo.
echo [4/4] Готово:
@@ -74,10 +50,38 @@ echo Двойной клик — GUI. Из консоли: md2gost.exe report.md
echo Повторно без clean — быстрее за счёт кэша Analysis.
echo Полный пересбор: build-exe-fast.bat clean
echo.
if "%DO_PAUSE%"=="1" pause
exit /b 0
:nopython
echo Python не найден в PATH. Установите Python 3.10+ и отметьте "Add python.exe to PATH".
goto :fail
:oldpython
echo Нужен Python 3.10 или новее.
python --version
goto :fail
:pipfail
echo Не удалось поставить зависимости.
goto :fail
:notemplate
echo Нет md2gost\Template.docx — сборка бессмысленна.
goto :fail
:nojar
echo Нет md2gost\vendor\plantuml.jar — portable exe без jar не собираем.
goto :fail
:pyifail
echo PyInstaller завершился с ошибкой.
goto :fail
:noexe
echo dist\md2gost.exe не появился.
goto :fail
:fail
echo.
echo Сборка не удалась.
+35 -30
View File
@@ -1,54 +1,35 @@
@echo off
setlocal EnableExtensions
chcp 65001 >nul
cd /d "%~dp0"
chcp 65001 >nul 2>&1
echo === md2gost: сборка exe ===
echo Каталог: %CD%
echo.
where python >nul 2>&1
if errorlevel 1 (
echo Python не найден в PATH. Установите Python 3.10+ и отметьте "Add python.exe to PATH".
goto :fail
)
if errorlevel 1 goto :nopython
python -c "import sys; raise SystemExit(0 if sys.version_info >= (3, 10) else 1)"
if errorlevel 1 (
echo Нужен Python 3.10 или новее.
python --version
goto :fail
)
python -c "import sys; raise SystemExit(sys.hexversion < 0x030A0000)"
if errorlevel 1 goto :oldpython
echo [1/4] Зависимости проекта + PyInstaller + matplotlib ...
python -m pip install -q -e . "pyinstaller>=6.0" "matplotlib>=3.7"
if errorlevel 1 (
echo Не удалось поставить зависимости.
goto :fail
)
if errorlevel 1 goto :pipfail
if not exist "md2gost\Template.docx" (
echo Нет md2gost\Template.docx — сборка бессмысленна.
goto :fail
)
if not exist "md2gost\Template.docx" goto :notemplate
echo [2/4] PlantUML jar (вшивается в exe, если скачается^) ...
echo [2/4] PlantUML jar, вшивается в exe если скачается ...
python scripts\fetch_plantuml.py
if not exist "md2gost\vendor\plantuml.jar" (
echo Предупреждение: plantuml.jar нет — в exe диаграммы пойдут через kroki.io.
)
echo [3/4] PyInstaller (один файл, без консоли; CLI подцепит консоль сам^) ...
echo [3/4] PyInstaller, один файл, без консоли; CLI подцепит консоль сам ...
python -m PyInstaller --noconfirm --clean md2gost.spec
if errorlevel 1 (
echo PyInstaller завершился с ошибкой.
goto :fail
)
if errorlevel 1 goto :pyifail
if not exist "dist\md2gost.exe" (
echo dist\md2gost.exe не появился.
goto :fail
)
if not exist "dist\md2gost.exe" goto :noexe
echo.
echo [4/4] Готово:
@@ -56,11 +37,35 @@ echo %CD%\dist\md2gost.exe
echo.
echo Двойной клик — GUI. Из консоли: md2gost.exe report.md -o report.docx
echo.
if /i "%~1"=="nopause" goto :eof
pause
exit /b 0
:nopython
echo Python не найден в PATH. Установите Python 3.10+ и отметьте "Add python.exe to PATH".
goto :fail
:oldpython
echo Нужен Python 3.10 или новее.
python --version
goto :fail
:pipfail
echo Не удалось поставить зависимости.
goto :fail
:notemplate
echo Нет md2gost\Template.docx — сборка бессмысленна.
goto :fail
:pyifail
echo PyInstaller завершился с ошибкой.
goto :fail
:noexe
echo dist\md2gost.exe не появился.
goto :fail
:fail
echo.
echo Сборка не удалась.
+2
View File
@@ -14,4 +14,6 @@
Исходный код конвертера: [`md2gost/`](../md2gost/). Примеры: [`examples/`](../examples/).
Полная карта репозитория (архитектура, все функции CLI/GUI и модули кода): [`PROJECT.md`](../PROJECT.md).
В GUI: **Справка → Документация** — тот же набор страниц (вшит в exe).