- OCaml 97.6%
- CSS 1.5%
- JavaScript 0.3%
- Standard ML 0.3%
- Dune 0.2%
- Other 0.1%
sto701c
Компилятор на OCaml, преобразующий Org-mode, Markdown (CommonMark + GFM) и MDX в PDF и DOCX, оформленные согласно стандарту для учебных текстов.
Оба выходных формата создаются собственными OCaml-писателями — никакие внешние бинарники во время работы не вызываются. Кириллица полностью поддерживается в PDF за счёт встроенных TrueType-шрифтов (по умолчанию DejaVu Serif).
Быстрый старт
mise install
mise run bootstrap
mise run deps
mkdir -p out
mise run run -- -i samples/diploma.md --pdf out/diploma.pdf --docx out/diploma.docx
После выполнения команды в out/ появятся diploma.pdf и diploma.docx.
Аргументы после -- передаются в сам CLI sto701c:
mise run run -- -i INPUT.md --pdf OUT.pdf --docx OUT.docx
# ^^ всё справа передаётся программе sto701c
Чтобы собрать все входные примеры из samples/, используйте:
mise run samples
Эта команда создаёт out/org.*, out/md.*, out/mdx.*,
out/coursework.*, out/diploma.*, out/nir.* и копирует краткое описание
примеров в out/README.md.
Документированный пример
Основной пример для копирования — samples/diploma.md. Он показывает
Markdown с YAML-предисловием, полный титульный лист дипломного проекта,
подписантов, автоматическую дату и обычное содержимое работы.
Соберите его отдельно:
mkdir -p out
mise run run -- -i samples/diploma.md --pdf out/diploma.pdf --docx out/diploma.docx
Минимальная структура такого файла:
---
title: Технологическое перевооружение производства глифталевых лаков
language: ru
ministry: Министерство науки и высшего образования Российской Федерации
university: Государственный технический университет
cathedra: Кафедра «Химическая технология органических покрытий»
udc: 667.633.26
doc_kind: ДП
subject: Химическая технология высокомолекулярных соединений
doc_code: УНИВЕР 240501.65-008 ДП
approval: Заведующий кафедрой | д-р хим. наук, профессор | И. В. Голиков | auto
supervisor: Руководитель | канд. техн. наук, доцент | М. П. Чагин |
consultant: Консультант по охране труда | канд. техн. наук, доцент | Е. Л. Белороссов |
normcontrol: Нормоконтролер | канд. техн. наук, доцент | М. П. Чагин |
student: | | А. А. Сидоров |
group: ХТЛ-54
year: 2026
---
# Введение
Текст работы начинается после YAML-предисловия.
Формат подписантов: Роль | Степень, звание | Имя | Дата.
Дата может быть явной (02.06.2026), автоматической (auto) или пустой для
ручного заполнения. Дополнительные пояснения по каждому файлу есть в
samples/README.md.
Титульный лист
Титульный лист построен по схеме из 15 модулей на формате A4. Данные передаются через ключевые слова; они работают и в Org, и в YAML-предисловии Markdown/MDX (в YAML ключи записываются строчными буквами).
| Ключ Org | Ключ YAML | Модуль | Примечания |
|---|---|---|---|
#+MINISTRY: |
ministry |
1 | верхняя центрированная строка (ведомство) |
#+UNIVERSITY: |
university |
1 | вторая центрированная строка |
#+CATHEDRA: |
cathedra |
1 | «Кафедра «...»» |
#+UDC: |
udc |
2 | индекс УДК, слева сверху |
#+APPROVAL: |
approval |
3 | блок «ДОПУСКАЕТСЯ К ЗАЩИТЕ» (только ДП/ДР); формат с ` |
#+GRADING: |
grading |
4 | готовая строка оценки (заменяет шаблон) |
#+GRADE: |
grade |
4 | слово-оценка, подставляется в шаблон |
#+DEFENDED_BY: |
defended_by |
4 | руководитель, подписавший оценку; формат с ` |
#+DOC_KIND: |
doc_kind / kind |
4,6,7 | ДП·ДР·КП·КР·ПО·ПУ·ПТ·ПП·РГР·РГЗ·ЛР·ОР |
#+SUBJECT: |
subject |
6 | специальность / дисциплина |
#+DOC_CODE: |
doc_code / code |
7 | шифр «УНИВЕР 240501.65-008 ДП» |
#+AGREED: |
agreed |
8 | принудительное «СОГЛАСОВАНО» (для ДП/ДР включается само) |
#+SUPERVISOR: |
supervisor |
9 | руководитель работы (ДП) |
#+CONSULTANT: |
consultant |
10–12 | повторяется для каждого консультанта |
#+NORMCONTROL: |
normcontrol |
13 | нормоконтролёр |
#+STUDENT: |
student |
14 | строка подписи студента; формат с ` |
#+GROUP: |
group |
14 | «ХТЛ-54» |
#+YEAR: |
year |
15 | пишется без слова «год» |
#+TOPIC: |
topic / doc_topic |
5 | заголовок темы (если отличается от #+TITLE:) |
#+SIGNATURE_STYLE: |
signature_style |
9–14 | slashes (по умолчанию) или inline (___Имя) |
#+DATE_STYLE: |
date_style |
9–14 | numeric (__.__.____) или verbose («___» __________ 2026) |
#+UPPERCASE_TITLE: |
uppercase_title |
5 | yes (по умолчанию) или no для длинных тем |
Поля #+MINISTRY: / #+UNIVERSITY: / #+CATHEDRA: в Org повторяются —
несколько строк подряд объединяются переносами. В YAML тот же эффект
достигается разделителем ; , например
university: ФГБОУ; высшего образования; «Университет».
Доступные значения #+DOC_KIND:: ДП (дипломный проект), ДР (дипломная работа),
КП / КР (курсовой проект/работа), ПО / ПУ / ПТ / ПП (виды практики),
РГР / РГЗ (расчётно-графическая работа/задание), ЛР (лабораторная работа),
ОР (обзорный реферат), НИР (научно-исследовательская работа).
Формат подписантов с разделителем |: Роль | Степень, звание | Имя Фамилия | ДД.ММ.ГГГГ.
- Строка подписи формируется автоматически:
- если имя заполнено, выводится
———————— /Имя Фамилия/(длинная черта под живую подпись и напечатанное имя в косых чертах для ясности); - если имя пустое, ставится более длинная черта и подпись
(подпись), чтобы документ можно было подписать от руки.
- если имя заполнено, выводится
- Поле даты принимает три формы:
- явная дата (
02.06.2026); - литерал
auto— заменяется на сегодняшнюю дату при компиляции документа; - пустое значение — выводится как
__.__.____для рукописного заполнения.
- явная дата (
- Поле оценки (
#+GRADE:/grade:) подставляется в предложение модуля 4 как... защищён с оценкой <grade>; если не задано, ставится__________для рукописного заполнения.
Пустые поля в конце можно опускать; пустые поля внутри строки нужно
оставлять между разделителями (Имя | | Фамилия |).
Если ни одно из этих полей не задано, писатель возвращается к простой
центрированной странице Title / Subtitle / Authors / Date, так что
существующие простые документы продолжают работать без изменений.
Пример (курсовая работа, Org)
#+TITLE: Исследование системы неразрушающего контроля
#+MINISTRY: Министерство науки и высшего образования Российской Федерации
#+UNIVERSITY: Государственный технический университет
#+CATHEDRA: Кафедра «Технология металлов»
#+UDC: 620.179
#+DOC_KIND: КР
#+SUBJECT: Основы технологического контроля
#+DOC_CODE: УНИВЕР 200503.65-007 КР
#+GRADE: отлично
#+DEFENDED_BY: Руководитель | канд. техн. наук, доцент | (личная подпись) Е. Ф. Трофимов | 02.06.2026
#+NORMCONTROL: Нормоконтролер | канд. техн. наук, доцент | (личная подпись) Е. Ф. Трофимов | 02.06.2026
#+STUDENT: | | (личная подпись) А. А. Ушаков | 02.06.2026
#+GROUP: ЭСК-42м
#+YEAR: 2026
Полные примеры — samples/coursework.org и samples/diploma.md.
Решения по оформлению
- Страница: A4 (×ばつ297 мм), поля слева 30 / справа 10 / сверху 20 / снизу 20 мм.
- Основной шрифт: Times New Roman, 14 пт, чёрный, одинарный
межстрочный интервал.
В PDF подставляется DejaVu Serif, потому что TNR не подлежит свободному
распространению. Для титульного листа можно подключать TTF через CSS
@font-faceи применять их черезfont-family. - Абзацный отступ: первая строка 12,5 мм (≈ 5 знаков), единый по всему документу.
- Нумерация разделов:
1,1.1,1.1.1,1.1.1.1— до 4 уровней. - Заголовки: первая буква заглавная, без точки, без подчёркивания, без переносов.
- Отбивка заголовков: 3 одинарных межстрочных интервала вокруг заголовков разделов, 2 — вокруг заголовков подразделов.
- Номера страниц: арабские, в правом верхнем углу; на титульном листе не выводятся.
- Таблицы: «Таблица N — Заголовок» над таблицей.
- Рисунки: «Рисунок N — Заголовок» под рисунком, по центру.
- Структурные ненумерованные заголовки (Содержание, Введение, Заключение, Список используемых источников, Приложение ...) центрируются и не нумеруются.
Инструменты: mise
В проекте используется mise для управления
инструментарием OCaml/opam и для запуска задач. Создаётся локальный
opam-switch (./_opam/), чтобы системный OCaml не затрагивался.
Первичная настройка
cd sto701c
mise install # ставит ocaml@5.2.1 и opam@2.3.0 из mise.toml
mise run bootstrap
mise run deps
Повседневные команды
| Задача | Что делает |
|---|---|
mise run build |
dune build в локальном switch |
mise run samples |
Сборка и компиляция samples/* в ./out/ |
mise run run -- -i FILE.org --pdf out.pdf --docx out.docx |
Запуск CLI на своём входе |
mise run clean |
dune clean и удаление out/ |
mise run test |
Заглушка для dune runtest |
mise run fmt |
dune build @fmt --auto-promote (если установлен ocamlformat) |
mise run сам подтягивает версии OCaml/opam проекта, после чего каждая
задача оборачивает свою команду в opam exec --switch=. --, чтобы dune
и зависимости разрешались относительно локального switch.
CLI
sto701c [-i PATH] [-f org|md|mdx] [--style STYLE.css] [--pdf OUT.pdf] [--docx OUT.docx]
-i / --input— путь к входному файлу (-— stdin; по умолчанию).-f / --format—org,mdилиmdx. Если не указан, определяется по расширению.--pdf/--docx— нужно указать хотя бы один.--style— путь к CSS-файлу. По умолчанию используетсяstyles/sto701.css, если файл есть. CSS из документа переопределяет файловые настройки. В CSS поддерживается@importс путями относительно файла, где он указан.
CSS-конфигурация
Базовая СТО-разметка лежит в styles/sto701.css. Компилятор берёт оттуда
размер страницы, поля и координаты областей титульного листа через @page и
вложенные правила вроде title-page header, title-page title,
title-page student. Шрифты для PDF можно подключать через
@font-face и применять через font-family внутри модулей.
@import "title-page.css";
@import url("fonts.css");
@font-face {
font-family: "TitleSerif";
src: url("DejaVuSerif.ttf");
}
@page {
size: 210mm 297mm;
margin: 20mm 10mm 20mm 30mm;
title-page title {
top: 96mm;
left: 30mm;
width: 170mm;
font-family: "TitleSerif";
font-size: 18pt;
font-weight: bold;
text-transform: uppercase;
}
}
Примеры
mise run samples
mise run run -- -i my-thesis.org --style styles/sto701.css --pdf thesis.pdf --docx thesis.docx
mise run run -- -i README.md --pdf out.pdf
cat draft.mdx | mise run run -- --pdf draft.pdf --docx draft.docx
Поддерживаемые возможности входа
Org (подмножество, влияющее на экспорт)
- Ключевые слова документа:
#+TITLE,#+SUBTITLE,#+AUTHOR,#+DATE,#+LANGUAGE,#+KEYWORDS,#+OPTIONS,#+MACRO,#+BIBLIOGRAPHY,#+TODO,#+CAPTION,#+NAME,#+ATTR_*. - Заголовки с состояниями TODO/DONE/WAITING, приоритетом
[#A], тегами:tags:. - Списки: маркированные (
-/+/*), нумерованные (1./1)), описательные (ТЕРМИН :: ОПР), вложенные, чек-боксы ([ ]/[X]). - Таблицы с разделителями
|---+---|и выравниванием:--:/:--/--:. - Блоки:
SRC,EXAMPLE,QUOTE,VERSE,CENTER,EXPORT,COMMENT. - Ящики:
:PROPERTIES:/:LOGBOOK:/:END:. - Определения и ссылки сносок (
[fn:NAME]). - Строчная разметка:
*жирный*,/курсив/,_подчёркнутый_,+зачёркнутый+,~код~,=verbatim=, нижний_{x}/ верхний^{x}индекс. - Математика:
$inline$,\(inline\),\[display\], плюс#+BEGIN_EXPORT latex. - Ссылки:
[[адрес][текст]]; расширения изображений определяются автоматически; префиксfile:. - Цитирование:
[cite:@key]. - Раскрытие макросов:
{{{name(arg)}}}из определений#+MACRO:. - Метки/якоря:
<<anchor>>. - Сырой экспорт:
@@latex:...@@,@@ooxml:...@@.
Исполнение блоков Babel сознательно не выполняется.
Markdown (CommonMark + GFM)
- YAML-предисловие (
---...---) сtitle,author,date,language,keywordsи произвольными ключами вmeta.custom. - ATX-заголовки (
#–######) и setext-заголовки (подчёркивание===/---). - Абзацы, цитаты (
> ...), тематические разделители (---/***/___). - Огороженные блоки кода (
```и~~~) с тегом языка. - Списки нумерованные и маркированные, с чек-боксами задач (
- [ ]/- [x]). - GFM-таблицы с правилом выравнивания (
|:--|:--:|--:|). - Строчный код (
`...`), курсив (*/_), полужирное (**/__), ссылки ([текст](url)), изображения ().
MDX
Обрабатывается как Markdown после удаления всех PascalCase JSX-тегов:
<Tag ...>, </Tag> и <Tag .../> удаляются; их содержимое сохраняется как
обычный Markdown. По условию задачи компоненты не отображаются в
пользовательские рендеры.
Структура проекта
Код разбит на небольшие, узконаправленные модули (ни один не превышает ~240 строк).
Внутри lib/ dune использует (include_subdirs unqualified), поэтому
каждый .ml становится одноуровневым модулем библиотеки Sto701c
независимо от папки.
sto701c/
mise.toml # инструментарий и задачи
dune-project # метаданные OCaml-проекта
bin/
main.ml # CLI (Cmdliner)
dune
lib/
dune
core/ # общие типы и проходы
ast.ml # AST документа
style.ml # профиль оформления
title_page.ml # модель титульного листа
numbering.ml # иерархическая нумерация разделов
parser/ # все парсеры входов
inline_ctx.ml # примитивы курсора сканирования
inline_emph.ml # помощники emphasis / ссылок
inline_parser.ml # строчная разметка (org + md)
org/
org_lexer.ml # построчный токенизатор org
org_helpers.ml # курсор, атрибуты, разбиение заголовков
org_tables.ml # таблицы `| ... |`
org_block_body.ml # сборщик тела #+BEGIN_xxx
org_blocks.ml # списки + ящики + основной парсер
org_parser.ml # мета + макросы + точка входа
md/
md_front.ml # YAML-предисловие
md_inline_helpers.ml # детект ATX/setext/fence/table/bullet
md_blocks.ml # взаимно рекурсивный парсер блоков
md_parser.ml # точка входа (вкл. срез JSX в MDX)
writer/
pdf/ # бэкенд PDF
pdf_encoding.ml # UTF-8 → Identity-H hex-глифы
ttf_metrics.ml # минимальный читатель TrueType
pdf_objects.ml # сборщик PDF-объектов + встраивание шрифтов
pdf_layout.ml # геометрия, прогоны, разбиение на строки
pdf_page.ml # состояние страницы + эмиттер строк
pdf_para.ml # абзац / заголовок / список
pdf_blocks.ml # код / таблица / рисунок / диспетчер
pdf_title.ml # титульный лист
pdf_writer.ml # сериализация + точка входа
docx/ # бэкенд DOCX
docx_runs.ml # rPr + строчные → OOXML-прогоны
docx_blocks.ml # абзацы / списки / таблицы / рисунки
docx_title.ml # титульный лист
docx_doc.ml # sectPr + сборка document.xml
docx_parts.ml # styles/numbering/settings/header xml
docx_writer.ml # упаковка в zip (точка входа)
samples/
sample.org sample.md sample.mdx
tests/ # заглушка
out/ # сгенерированные выходы (mise run samples)
Зависимости (ставятся mise run deps)
dune3.x — система сборкиcamlzip— ZIP-контейнер для DOCXcamlpdf— подключён на будущее (текущий PDF-писатель самописный)uutf,uucp— Unicode-утилитыre— регулярные выраженияcmdliner— разбор CLI
Ограничения
- Встроенные изображения отображаются как текст-заглушка (alt) в DOCX и
как блоки
[caption]в PDF. Встраивание пикселей оставлено на будущее. - Рендер таблиц в PDF обрезает слишком длинный текст ячейки до одной строки.
- LaTeX-математика отображается курсивом, без типографского набора.
- Стилизация DOCX использует стиль
Normalпо умолчанию — настройте собственныйreference.docx, если нужны дополнительные именованные стили.