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

# HEBREW_HOMEWORK_TO_WORD

Skill преобразует markdown-файлы с выполненными домашними заданиями по ивриту в DOCX.

Используется в пайплайне подготовки домашних заданий, после скила `hebrew-homework-solve`.

---

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

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

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

```
ДЗ_урок_{N}_часть_{M}_слайды_{СЛАЙДЫ}.md
```

или (если слайды не указаны):

```
ДЗ_урок_{N}_часть_{M}.md
```

В суффиксе `{СЛАЙДЫ}`:
- дефис `-` означает диапазон (от и до): `25-28` = слайды 25, 26, 27, 28
- подчёркивание `_` — разделитель между элементами: `25-28_30` = слайды 25–28 и 30

Примеры:

```
ДЗ_урок_13_часть_3_слайды_25_26.md
ДЗ_урок_13_часть_3_слайды_25-28.md
ДЗ_урок_13_часть_3_слайды_25-28_30_33-35.md
```

---

# Результат

Один DOCX файл на каждый входной markdown.

Имя формируется автоматически — расширение `.md` заменяется на `.docx`.

Пример:

ДЗ_урок_13_часть_3_слайды_25_26.md → ДЗ_урок_13_часть_3_слайды_25_26.docx

Если подано несколько файлов, генерируется отдельный docx для каждого.

---

# Структура markdown домашнего задания

Markdown от скила `hebrew-homework-solve` имеет следующую структуру:

```
# Домашнее задание — Урок N, часть M

---

## Слайд X — [тип упражнения]

[инструкция на иврите]

| Текст | № |
|---|---|
| [предложение на иврите] | 1 |
| [перевод на русский] |   |
| [предложение на иврите] | 2 |
| [перевод на русский] |   |

---

## Слайд Y — [тип упражнения]

...
```

Или для текстов чтения:

```
## Слайды X–Y — Текст для чтения

[инструкция на иврите]

### [Заголовок текста на иврите]

[абзац на иврите]

[перевод абзаца на русском]

[следующий абзац на иврите]

[перевод]
```

Или для классификации:

```
## Слайд X — Упражнение: классификация глаголов

[инструкция на иврите]

[список глаголов]

### Группа 1

[слова с переводами]

### Группа 2

[слова с переводами]
```

---

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

Алгоритм определения языка для каждого параграфа/run:

1. Если текст содержит символы Unicode в диапазонах \u0590–\u05FF (Hebrew) или \u0591–\u05C7 (Hebrew nikud), это **иврит**
2. Если текст содержит символы Unicode в диапазоне \u0400–\u04FF (Cyrillic), это **русский**
3. Если текст содержит оба — нужно разбить на runs по границам скриптов

Функция определения:

```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

## Заголовок документа

`# Домашнее задание — Урок N, часть M`

- Heading 1
- font: Arial
- size: 14pt (28 half-points)
- bold
- alignment: center
- spacing after: 200

---

## Заголовки слайдов

`## Слайд X — [тип]` или `## Слайды X–Y — [тип]`

- Heading 2
- font: Arial
- size: 13pt (26 half-points)
- bold
- alignment: left
- spacing before: 240, after: 120

---

## Подзаголовки

`### текст`

Используются для:
- заголовков текстов на иврите (### סִיפּוּרִים של פעם)
- названий групп в упражнениях классификации

Если текст на иврите:
- font: David
- size: 16pt (32 half-points)
- bold
- alignment: right
- direction: RTL

Если текст на русском:
- font: Arial
- size: 10pt (20 half-points)
- bold
- alignment: left

---

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

### Иврит

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

### Русский

- font: Arial
- size: 10pt (20 half-points)
- alignment: left
- spacing after: 120

### Смешанный текст (иврит + русский в одном абзаце)

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

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

---

## Нумерованные пункты (устаревший формат)

> **Примечание:** Упражнения в текущем формате оформляются как markdown-таблицы `| Текст | № |`, а не как нумерованные списки. Этот раздел сохранён для обратной совместимости с материалами, которые могут содержать строки `1. [текст]`.

Строки вида `1. [текст]`, `2. [текст]` и т.д.

Парсинг:
1. Извлечь номер и текст
2. Номер — отдельный run (Arial 10pt)
3. Текст — определить язык, применить соответствующий шрифт
4. Если в тексте есть `(**слово**)` — вставленное слово, выделить жирным

Перевод/объяснение на следующей строке (без пустой строки) — отдельный параграф, Arial 10pt.

---

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

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

---

## Курсив

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

---

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

`---` между секциями (слайдами).

Поведение: вставить разрыв страницы (page break) перед следующей секцией `## Слайд`. Каждое упражнение начинается с новой страницы.

---

## Инструкции на иврите

Строки, состоящие целиком из ивритского текста (не являющиеся частью нумерованного списка и не являющиеся заголовком).

- font: David
- size: 18pt (36 half-points)
- bold
- alignment: right
- direction: RTL
- spacing after: 120

Определяется как: строка не начинается с `#`, не начинается с цифры+точки, целиком содержит иврит (+ пунктуация/пробелы).

---

## Таблицы

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

Заголовки таблиц удаляются (строка заголовка и строка-разделитель не попадают в DOCX).

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

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

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

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

### Размещение и ширина

Для таблиц обязательно используются следующие правила Word:

- таблица занимает 100% ширины текстовой области
- `AutoFit` не используется
- используется фиксированная ширина колонок (`AutoFit = Fixed`)
- перенос текста внутри ячеек разрешён
- строка таблицы не разрывается между страницами (`Allow row to break across pages = false`)

**Ширина колонок зависит от типа таблицы:**

- **Таблицы упражнений** (`| Текст | № |`) — колонка «Текст» широкая (~90%), колонка «№» узкая (~10%). Порядок колонок в markdown: сначала «Текст», потом «№» — чтобы в docx без зеркалирования получился правильный RTL-порядок (номер справа, текст слева)
- **Таблицы спряжения** и прочие таблицы — ширина колонок распределяется равномерно

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

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

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

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

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

### Иврит в таблицах

Ячейки с ивритом:
- font: David
- size: 18pt (36 half-points)
- alignment: right
- direction: RTL
- complex script markers обязательны

Ячейки с русским:
- font: Arial
- size: 10pt (20 half-points)
- alignment: left

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

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

Для иврита в таблицах нужны настройки на ДВУХ уровнях:

**Уровень параграфа (Paragraph)** — обязательно для каждого параграфа с ивритом внутри ячейки:
- `alignment: AlignmentType.RIGHT`
- `bidirectional: true`

**Уровень run (TextRun)** — обязательно для каждого ивритского фрагмента:
- обычный шрифт `David`
- complex script font `David`
- `rightToLeft: true`
- `size: 36` и `sizeCs: 36` (18pt)
- `boldCs: true` если нужен жирный

Пример ячейки с ивритом:

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

Если в одной ячейке смешаны русский и иврит, форматирование назначается только соответствующим фрагментам текста, а не всей ячейке целиком. Параграф выравнивается вправо (`alignment: RIGHT, bidirectional: true`), русские runs получают шрифт Arial 10pt без `rightToLeft`.

---

## Строки «Выбрано: ...» (объяснения выбора)

Строки, начинающиеся с «Выбрано:» — содержат смешанный текст. В текущем формате появляются внутри ячеек таблицы упражнений (колонка «Текст»).

- Основной шрифт: Arial 10pt
- Ивритские слова внутри: David 18pt, RTL run
- Слово после «Выбрано:» — жирное

---

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

Разрыв страницы вставляется перед каждым заголовком `## Слайд` (кроме самого первого).

Технически: параграф Heading 2 получает `pageBreakBefore: true`, за исключением первого Heading 2 в документе.

```javascript
new Paragraph({
  heading: HeadingLevel.HEADING_2,
  pageBreakBefore: !isFirstSlide,
  children: [ ... ]
})
```

---

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

A4 (по умолчанию):

верхнее: 1.27 см (720 twips)
нижнее: 1.27 см (720 twips)
левое: 1.27 см (720 twips)
правое: 1.27 см (720 twips)

---

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

## BiDi и RTL

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

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

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

```javascript
styles: {
  default: {
    document: {
      run: { font: "Arial", size: 20 } // 10pt по умолчанию
    }
  },
  paragraphStyles: [
    {
      id: "Heading1", name: "Heading 1",
      basedOn: "Normal", next: "Normal", quickFormat: true,
      run: { size: 28, bold: true, font: "Arial" },
      paragraph: { spacing: { after: 200 }, alignment: AlignmentType.CENTER }
    },
    {
      id: "Heading2", name: "Heading 2",
      basedOn: "Normal", next: "Normal", quickFormat: true,
      run: { size: 26, bold: true, font: "Arial" },
      paragraph: { spacing: { before: 240, after: 120 } }
    }
  ]
}
```

## Правила для 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: Классифицировать каждую строку

Для каждой строки определить тип:

| Паттерн | Тип |
|---------|-----|
| `^# ` (один #) | heading1 |
| `^## ` | heading2 |
| `^### ` | heading3 |
| `^---$` | separator |
| `^\d+\. ` | numbered_item (устаревший формат, для обратной совместимости) |
| `^\|` | table_row |
| Пустая строка | blank |
| Строка целиком на иврите | hebrew_paragraph |
| Строка начинается с «Выбрано:» | explanation |
| Остальное | text_paragraph |

### Распознавание таблиц упражнений

Таблица упражнений определяется по заголовку `| Текст | № |`. Для таких таблиц:
- Первая колонка («Текст») — широкая (~90%), содержит иврит, перевод, объяснение
- Вторая колонка («№») — узкая (~10%), содержит номер пункта или пустую ячейку
- Язык каждой ячейки определяется автоматически для выбора шрифта и направления

Все остальные таблицы (спряжения и т.д.) обрабатываются с равномерным распределением ширины колонок.

## Шаг 3: Определить язык строки

Для строк типа `hebrew_paragraph` и `text_paragraph`:
- Подсчитать количество ивритских и кириллических символов
- Если иврит > кириллица → иврит
- Если кириллица > иврит → русский
- Если примерно поровну → смешанный (разбивать на runs)

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

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

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

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

---

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

Для разбиения строки на runs с разными стилями:

```javascript
function parseInlineFormatting(text) {
  const runs = [];
  // Регулярное выражение для **bold** и *italic*
  const regex = /(\*\*(.+?)\*\*)|(\*(.+?)\*)|([^*]+)/g;
  let match;
  while ((match = regex.exec(text)) !== null) {
    if (match[2]) {
      // bold
      runs.push({ text: match[2], bold: true });
    } else if (match[4]) {
      // italic
      runs.push({ text: match[4], italic: true });
    } else if (match[5]) {
      // normal
      runs.push({ text: match[5], bold: false, italic: false });
    }
  }
  // Далее каждый run разбить по языковым границам
  return runs.flatMap(run => splitByScript(run));
}
```

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

---

# Validation

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

1. Файл должен начинаться с `# Домашнее задание`
2. Файл должен содержать хотя бы одну секцию `## Слайд`
3. Markdown-таблицы (если есть) должны иметь корректную структуру

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

---

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

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

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

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

---

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

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

- [ ] Документ открывается без ошибок
- [ ] Иврит отображается шрифтом David, 18pt, выравнивание вправо, RTL
- [ ] Русский текст — Arial 10pt, выравнивание влево
- [ ] Каждое упражнение начинается с новой страницы
- [ ] Таблицы не разорваны между страницами (строка целиком на одной странице)
- [ ] Жирный шрифт на вставленных словах сохранён
- [ ] Смешанный текст (иврит + русский в одной ячейке) корректно отформатирован

---

# Скрипт

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

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

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

Запуск:

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

Примеры:

```bash
python scripts/build_homework_docx.py ДЗ_урок_13_часть_3_слайды_25_26.md
python scripts/build_homework_docx.py ДЗ_урок_13_часть_3_слайды_25_26.md -o out.docx
python scripts/build_homework_docx.py file1.md file2.md
```

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

---

# References

references/ДЗ_урок_14_часть_1_9-13_25.md
references/ДЗ_урок_14_часть_1_27-29.md
