---
name: hebrew-lesson-docx
description: >
  Преобразование markdown-шпаргалок (грамматических справочников) по ивриту в форматированный DOCX.
  Используй этот skill, когда пользователь просит сгенерировать Word-документ из шпаргалки,
  создать DOCX из результата скила hebrew-lesson-enrich, собрать шпаргалку в Word,
  или упоминает файлы вида «Шпаргалка_по_*» в контексте создания документа.
  Также используй при любом упоминании «сделай docx из шпаргалки», «собери шпаргалку в Word»,
  «подготовь шпаргалку для печати» в контексте грамматических справочников по ивриту.
  НЕ использовать для домашних заданий — для них есть hebrew-homework-docx.
---

# HEBREW_LESSON_TO_WORD

Skill преобразует markdown-файлы с грамматическими шпаргалками по ивриту в DOCX.

Используется в пайплайне подготовки учебных материалов, после скила `hebrew-lesson-enrich`.

---

# Входные данные

Skill принимает markdown-файл — выход скила `hebrew-lesson-enrich`.
Если скил `hebrew-lesson-enrich` ещё не выполнялся — предложить пользователю сначала запустить его.

Формат имени:

```
Шпаргалка_по_{N}_уроку_{M}_часть.md
```

Пример:

```
references/Шпаргалка_по_14_уроку_1_часть.md
```

---

# Результат

Один DOCX файл. Имя формируется заменой `.md` → `.docx`.

Пример:

```
Шпаргалка_по_14_уроку_1_часть.md → Шпаргалка_по_14_уроку_1_часть.docx
```

---

# Отличия от hebrew-homework-docx (домашние задания)

Шпаргалка — это грамматический справочник, а не рабочая тетрадь.
Ключевые отличия от DOCX домашних заданий:

| Аспект | Домашнее задание | Шпаргалка |
|--------|-----------------|-----------|
| Структура | Плоская: `## Слайд N` | Иерархическая: `# 1.` → `## 1.1` → `### 1.1.1` |
| Blockquotes | Нет | Есть — ключевые правила |
| Маркированные списки | Нет | Есть (`*` и `-`) |
| Разрывы страниц | Нет | Да — перед каждым `# N.` (кроме первого раздела) |
| Нумерованные пункты | Упражнения `1. текст` | Нет (нумерация только в заголовках) |
| «Выбрано: ...» | Есть | Нет |
| Символ ↳ | Нет | Есть (в сводных таблицах глаголов) |
| Иврит в таблицах | 14pt | 18pt |
| Объём | 2–5 страниц | 8–20 страниц |

---

# Структура markdown шпаргалки

```
# Шпаргалка по N уроку — часть M
## שיעור N חלק M
---

# 1. [Грамматическая тема]
## 1.1 [Подтема]
[текст на русском]

> Ключевое правило в blockquote

## 1.2 [Подтема]

| Таблица | спряжения |
|---|---|

## 1.3 Контрастные примеры

[иврит первой строкой]
[русский перевод второй строкой]

---

# 2. [Следующая тема]
...

---

# N. Сводная таблица глаголов
## N.1 שלמים

| С огласовками | Без огласовок | Перевод |
|---|---|---|

---

# N+1. Новые слова урока
## N+1.1 Существительные (שמות עצם)

| С огласовками | Без огласовок | Перевод |
|---|---|---|

---

# N+2. Сводная таблица глаголов с שם פעולה

| С огласовками | Без огласовок | Перевод |
|---|---|---|
| **להוריד** | להוריד | спускать |
| ↳ הוֹרָדָה | הורדה | спуск |
```

---

# Определение языка текста

Алгоритм определения языка — тот же, что в hebrew-homework-docx:

```javascript
function isHebrew(char) {
  const code = char.codePointAt(0);
  return (code >= 0x0590 && code <= 0x05FF) || (code >= 0xFB1D && code <= 0xFB4F);
}

function isCyrillic(char) {
  const code = char.codePointAt(0);
  return code >= 0x0400 && code <= 0x04FF;
}
```

Для смешанных строк — разбивать на runs по границам скриптов.

---

# Правила обработки markdown

## Заголовок документа (H1 — первый)

`# Шпаргалка по N уроку — часть M`

- Heading 1
- font: Arial
- size: 16pt (32 half-points)
- bold
- alignment: center
- spacing after: 80

---

## Подзаголовок на иврите (H2 — первый)

`## שיעור N חלק M`

- font: David
- size: 16pt (32 half-points)
- bold
- alignment: center
- direction: RTL
- bidirectional: true
- spacing after: 200

---

## Заголовки разделов (H1 — нумерованные)

`# 1. [Тема]`, `# 2. [Тема]` и т.д.

- Heading 1
- font: Arial
- size: 14pt (28 half-points)
- bold
- alignment: left
- spacing before: 0, after: 160
- **Разрыв страницы перед каждым** (кроме `# 1.`)

Если заголовок содержит иврит (например, `# 6. שם פעולה — отглагольные существительные`),
нужно разбить на runs: ивритская часть → David 14pt RTL, русская → Arial 14pt.

---

## Подзаголовки (H2 — нумерованные)

`## 1.1 [Подтема]`, `## N.1 שלמים` и т.д.

- Heading 2
- font: Arial (или David для ивритских)
- size: 13pt (26 half-points)
- bold
- alignment: left (или right для ивритских)
- spacing before: 200, after: 100

Определение языка: если более 50% символов — иврит, то David + RTL + right alignment.

---

## Подподзаголовки (H3)

`### הווה (настоящее время)` и т.д.

- font: Arial (или David для ивритских)
- size: 12pt (24 half-points)
- bold
- alignment: по языку
- spacing before: 160, after: 80

---

## Основной текст

### Иврит (абзац целиком на иврите)

- font: David
- size: 18pt (36 half-points)
- alignment: right
- direction: RTL
- bidirectional: true
- spacing after: 80

### Русский

- font: Arial
- size: 12pt (24 half-points)
- alignment: left
- spacing after: 80

### Смешанный текст

Разбивать на runs:
- Каждый ивритский фрагмент → run с David 18pt, RTL
- Каждый русский фрагмент → run с Arial 12pt

Абзац выравнивается по доминирующему языку.

---

## Контрастные пары (иврит + перевод)

В шпаргалке часто встречаются пары:
```
הַיֶּלֶד יוֹרֵד לָרְחוֹב.
Ребёнок спускается на улицу.
```

Определяются как: две последовательные непустые строки, первая — иврит, вторая — русский.

- Строка на иврите: David 18pt, RTL, right, spacing after: 0
- Строка на русском: Arial 12pt, left, spacing after: 120

Пустая строка между парами — spacing 80.

---

## Blockquotes (цитаты с правилами)

Строки, начинающиеся с `> `.

Оформление: **левая граница (border left) + отступ**.

```javascript
new Paragraph({
  indent: { left: 720 }, // 0.5 дюйма = 720 twips
  border: {
    left: {
      style: BorderStyle.SINGLE,
      size: 12,          // толщина 1.5pt
      color: "4472C4",   // синий
      space: 8,
    }
  },
  spacing: { before: 80, after: 80 },
  children: [/* runs */]
})
```

Текст внутри blockquote:
- Русский: Arial 12pt, **bold**
- Иврит: David 18pt, RTL, **bold**

Многострочные blockquotes (несколько строк подряд с `>`) — каждая строка
отдельный параграф с тем же форматированием.

---

## Маркированные списки

Строки, начинающиеся с `* ` или `- `.

- Отступ слева: 720 twips (0.5 дюйма)
- Символ маркера: `•` (bullet, U+2022) — отдельный run, Arial 12pt
- После маркера — пробел, затем текст
- Шрифт определяется по языку содержимого
- Spacing after: 40

```javascript
new Paragraph({
  indent: { left: 720, hanging: 360 },
  spacing: { after: 40 },
  children: [
    new TextRun({ text: "• ", font: { name: "Arial" }, size: 24 }),
    // далее runs текста
  ]
})
```

Если элемент списка содержит `**bold**` — обработать как inline bold.

---

## Таблицы

Markdown-таблицы преобразуются в таблицы Word.

### Поведение таблиц

Таблицы могут продолжаться на следующей странице.

Строка таблицы не может разрываться между страницами.

Если строка не помещается на текущей странице,
она переносится целиком на следующую страницу.

### Общие правила

- таблица занимает 100% ширины текстовой области
- `AutoFit` не используется
- используется фиксированная ширина колонок (`AutoFit = Fixed`)
- столбцы распределяются равномерно (если не указано иное)
- перенос текста внутри ячеек разрешён
- строка таблицы не разрывается между страницами (`Allow row to break across pages = false`)
- Заголовки таблиц (первая строка) — **жирные**, с серым фоном `"D9E2F3"` (светло-синий)
- Внешние границы: thin single
- Внутренние границы: thin single

### Глубина форматирования

Форматирование таблицы не должно применяться только «в целом по таблице».

Форматирование должно назначаться:

- на уровне paragraph / cell для направления текста
- на уровне run для шрифта и complex script

Это особенно важно для смешанных таблиц с ивритом и русским.

### Размеры шрифтов в таблицах

| Элемент | Шрифт | Размер |
|---------|-------|--------|
| Иврит в ячейке | David | 18pt (36 half-points) |
| Русский в ячейке | Arial | 12pt (24 half-points) |
| Заголовок таблицы (иврит) | David | 16pt (32 half-points), bold |
| Заголовок таблицы (русский) | Arial | 12pt (24 half-points), bold |

### RTL в ячейках

Ячейки с ивритом:
- alignment: right
- direction: RTL
- bidirectional: true
- Обязательно `rightToLeft: true` на TextRun
- Обязательно `sizeCs` равен `size`

### Практическое правило для Hebrew runs в таблицах

Нельзя ограничиваться установкой только `w:rFonts`.

Для иврита в таблицах одновременно должны быть выставлены:
- обычный шрифт `David`
- complex script font `David`
- `w:rtl`
- `w:cs`
- `w:sz` и `w:szCs`

Если в одной ячейке смешаны русский и иврит, форматирование назначается только соответствующим фрагментам текста, а не всей ячейке целиком.

### Символ ↳ в таблицах

Символ `↳` встречается в сводных таблицах глаголов с שם פעולה.
Обрабатывается как обычный текстовый символ. Шрифт: Arial (не David).
Пример ячейки: `↳ הוֹרָדָה` → run "↳ " (Arial 12pt) + run "הוֹרָדָה" (David 18pt RTL).

### Bold инфинитивы в сводных таблицах

В сводных таблицах с ↳ инфинитивы выделены жирным: `**להוריד**`.
Bold обрабатывается через стандартный inline-парсинг `**...**`.

---

## Горизонтальные разделители

`---` между крупными разделами.

Поведение: **игнорируются** — разрывы страниц вставляются по заголовкам `# N.`,
а `---` служат лишь визуальным маркером в markdown.

---

## Жирный текст

`**текст**` — bold run. Шрифт определяется по языку содержимого.

При bold для иврита обязательно задавать и `bold: true`, и `boldCs: true`.

---

## Курсив

`*текст*` — italic run (используется редко в шпаргалках).

---

# Разрывы страниц

Разрыв страницы вставляется **перед каждым заголовком `# N.`** (Heading 1),
кроме самого первого раздела `# 1.`.

Заголовок документа (`# Шпаргалка по...`) и ивритский подзаголовок (`## שיעור...`)
находятся на первой странице вместе с `# 1.`.

Реализация:

```javascript
// Перед H1 (кроме первого)
new Paragraph({
  pageBreakBefore: true,
  heading: HeadingLevel.HEADING_1,
  children: [/* runs */]
})
```

---

# Поля страницы

A4:

- верхнее: 2.0 см (1134 twips)
- нижнее: 2.0 см (1134 twips)
- левое: 2.0 см (1134 twips)
- правое: 2.0 см (1134 twips)

Поля чуть меньше стандартных (2.54 см), т.к. шпаргалка — справочный документ,
и дополнительное пространство для таблиц полезно.

---

# Технические требования к python-docx

## BiDi и RTL

Для каждого параграфа с ивритом:

```javascript
new Paragraph({
  alignment: AlignmentType.RIGHT,
  bidirectional: true,
  children: [
    new TextRun({
      text: hebrewText,
      font: { name: "David" },
      size: 36,           // 18pt
      sizeCs: 36,
      rightToLeft: true,
    })
  ]
})
```

## Стили документа

```javascript
styles: {
  default: {
    document: {
      run: { font: "Arial", size: 24 }
    }
  },
  paragraphStyles: [
    {
      id: "Heading1", name: "Heading 1",
      basedOn: "Normal", next: "Normal", quickFormat: true,
      run: { size: 28, bold: true, font: "Arial" },
      paragraph: { spacing: { after: 160 } }
    },
    {
      id: "Heading2", name: "Heading 2",
      basedOn: "Normal", next: "Normal", quickFormat: true,
      run: { size: 26, bold: true, font: "Arial" },
      paragraph: { spacing: { before: 200, after: 100 } }
    },
    {
      id: "Heading3", name: "Heading 3",
      basedOn: "Normal", next: "Normal", quickFormat: true,
      run: { size: 24, bold: true, font: "Arial" },
      paragraph: { spacing: { before: 160, after: 80 } }
    }
  ]
}
```

## Правила для runs с ивритом

ВАЖНО: При создании TextRun для иврита ВСЕГДА задавать ВСЕ свойства:

```javascript
new TextRun({
  text: "ивритский текст",
  font: { name: "David" },
  size: 36,           // 18pt
  sizeCs: 36,         // complex script размер
  rightToLeft: true,  // RTL
  bold: false,        // или true
  boldCs: false,      // или true
})
```

Без `sizeCs`, `boldCs` и `rightToLeft` иврит отображается неправильно.

---

# Алгоритм парсинга markdown

## Шаг 1: Разбить на строки

Разбить весь текст на строки. Обработать последовательно.

## Шаг 2: Классифицировать каждую строку

| Паттерн | Тип |
|---------|-----|
| `^# Шпаргалка` | doc_title |
| `^## שיעור` | doc_subtitle_hebrew |
| `^# \d+\.` | section_heading (H1 нумерованный) |
| `^## \d+\.\d+` | subsection_heading (H2 нумерованный) |
| `^### ` | subsubsection_heading (H3) |
| `^---$` | separator (игнорировать) |
| `^> ` | blockquote |
| `^\* ` или `^- ` | bullet_item |
| `^\|` | table_row |
| Пустая строка | blank |
| Строка целиком на иврите | hebrew_paragraph |
| Остальное | text_paragraph |

## Шаг 3: Контекстная обработка

### Контрастные пары

Если за `hebrew_paragraph` сразу идёт `text_paragraph` (русский) без пустой строки —
это контрастная пара. Обработать особо: иврит с spacing after: 0,
русский с spacing after: 120.

### Таблицы

Таблица начинается с `table_row`, продолжается пока идут `table_row`.
Вторая строка таблицы (с `---`) — разделитель, пропускается.

### Многострочные blockquotes

Последовательные строки с `> ` — один блок цитаты.
Каждая строка — отдельный параграф с одинаковым форматированием (border + indent).

## Шаг 4: Сгенерировать параграфы Word

Для каждой строки создать соответствующий параграф(ы).

## Шаг 5: Обработка inline-форматирования

Внутри каждого текстового фрагмента:
1. Найти `**текст**` → bold run
2. Найти `*текст*` → italic run (не совпадающий с **)
3. Разбить оставшийся текст по границам скриптов (иврит/русский/латиница)

---

# Обработка inline-форматирования

```javascript
function parseInlineFormatting(text) {
  const runs = [];
  const regex = /(\*\*(.+?)\*\*)|(\*(.+?)\*)|([^*]+)/g;
  let match;
  while ((match = regex.exec(text)) !== null) {
    if (match[2]) {
      runs.push({ text: match[2], bold: true });
    } else if (match[4]) {
      runs.push({ text: match[4], italic: true });
    } else if (match[5]) {
      runs.push({ text: match[5], bold: false, italic: false });
    }
  }
  return runs.flatMap(run => splitByScript(run));
}
```

Функция `splitByScript` разбивает один run на несколько,
если в нём смешаны иврит и русский/латиница.

---

# Обработка символа ↳

Символ ↳ (U+21B3, DOWNWARDS ARROW WITH TIP RIGHTWARDS) встречается
в сводных таблицах глаголов с отглагольными существительными.

При обработке ячейки таблицы, содержащей `↳ הוֹרָדָה`:

```javascript
// Разбить: "↳ " — Arial, "הוֹרָדָה" — David RTL
[
  new TextRun({ text: "↳ ", font: { name: "Arial" }, size: 24 }),
  new TextRun({
    text: "הוֹרָדָה",
    font: { name: "David" },
    size: 36, sizeCs: 36,
    rightToLeft: true,
  })
]
```

Ячейка с ↳ — выравнивание RIGHT, bidirectional: true
(чтобы иврит отображался корректно).

---

# Validation

Перед генерацией выполняются проверки:

1. Файл должен начинаться с `# Шпаргалка` или `# Грамматика`
2. Файл должен содержать хотя бы один нумерованный раздел `# \d+\.`
3. Markdown-таблицы (если есть) должны иметь корректную структуру

Если валидация не пройдена — сообщить об ошибке, не генерировать частичный документ.

---

# Поведение при ошибке

Если ошибка обнаружена при генерации:

1. Сообщить пользователю о проблеме
2. Показать конкретную строку/секцию с ошибкой
3. Предложить варианты исправления

Частичный документ не создаётся.

---

# Проверка выхода

После генерации DOCX проверить:

- [ ] Документ открывается без ошибок
- [ ] Иврит отображается шрифтом David, 18pt, выравнивание вправо, RTL
- [ ] Русский текст — Arial 12pt, выравнивание влево
- [ ] Разрывы страниц перед каждым `# N.` (кроме первого раздела)
- [ ] Blockquotes с левой синей границей и отступом
- [ ] Таблицы: заголовки жирные с серым фоном, не разорваны между страницами
- [ ] Символ ↳ в сводных таблицах отображается корректно (Arial, не David)
- [ ] Смешанный текст (иврит + русский) корректно отформатирован

---

# Реализация

Генерация реализована скриптом `scripts/build_lesson_docx.py`.

Зависимости:

```bash
pip install python-docx
```

Запуск:

```bash
python scripts/build_lesson_docx.py <markdown...> [-o output.docx]
```

Примеры:

```bash
python scripts/build_lesson_docx.py Шпаргалка_по_14_уроку_2_часть.md
python scripts/build_lesson_docx.py Шпаргалка_по_14_уроку_2_часть.md -o out.docx
python scripts/build_lesson_docx.py file1.md file2.md
```

Флаг `-o` работает только с одним входным файлом. При нескольких файлах DOCX создаётся рядом с каждым `.md`.

---

# Зависимости

- Python 3
- пакет `python-docx`

---

# References

`references/` — папка с эталонными входными markdown-файлами, если они добавлены в skill.
