| 1 | # Intent-based Melody Language (IML) v1 |
| 2 | |
| 3 | Документ фиксирует **язык ввода команд в палитре** с префиксом **`c:`** — тот же контракт, что в [ADR 0060 §11](adr/0060-keyboard-chord-stack-fms-tactical-strategic.md#adr0060-p11) (**Command Melody**). Здесь — **формальное описание**, мотивация и **открытые вопросы** для эволюции. |
| 4 | |
| 5 | **Связь:** [0060](adr/0060-keyboard-chord-stack-fms-tactical-strategic.md) (норматив продукта и паритет с аккордом), [0030](adr/0030-command-ids-hotkeys-and-ui-registry-layers.md) (`command_id`), [0072](adr/0072-chat-topic-cards-intent-melody-keyboard-contract.md) (chat-topic navigation как частный случай intent-first входов), [0109](adr/0109-declarative-parametric-melody-catalog-toml-and-code-binders.md) (каталог корней **`[[melody_root]]`** в TOML, параметрические сигнатуры хвоста), [chord-notation-cascadeide.md](chord-notation-cascadeide.md) (физические клавиши и Vim-нотация — **другой** слой). |
| 6 | |
| 7 | --- |
| 8 | |
| 9 | ## 1. Назначение |
| 10 | |
| 11 | **IML** — это не нотация клавиш, а **текстовый язык намерений** в строке палитры: короткие мнемоники, однозначно привязанные к **`command_id`** в реестре. Он дополняет fuzzy-поиск по human title и **не заменяет** канонический идентификатор команды. |
| 12 | |
| 13 | **Три представления одной команды** (как в 0060): |
| 14 | |
| 15 | | Слой | Пример | |
| 16 | |------|--------| |
| 17 | | Human title | `Git: Status` | |
| 18 | | Melody (IML) | `c: gs` (см. §3.2) | |
| 19 | | Canonical id | `git.status` | |
| 20 | |
| 21 | --- |
| 22 | |
| 23 | ## 2. Цели дизайна |
| 24 | |
| 25 | 1. **Intent-first:** пользователь вводит **домен → объект → намерение** (см. §3.2), а не координаты UI. Допускается **сжатая** форма из двух букв, когда **объект** подразумевается контекстом. |
| 26 | 2. **Паритет поверхностей:** тот же смысл доступен из палитры (строка), **CascadeChord** (`Ctrl+K` → буквы по [0060](adr/0060-keyboard-chord-stack-fms-tactical-strategic.md)) и MCP (`ide_execute_command` с тем же `command_id`) — [0008](adr/0008-mcp-contracts-and-testable-infrastructure.md). |
| 27 | 3. **Стабильность:** при смене формулировки в UI alias может оставаться неизменным. |
| 28 | 4. **Обход хрупкости глобальных жестов:** ввод в палитре **не зависит** от того, что ОС/IME/фокус доставили одну **сложную** комбинацию модификаторов + букву в одном событии (см. §8). |
| 29 | 5. **Частота → длина (эвристика):** чем **типичнее** команда для рабочего дня разработчика, тем **короче** разумный alias в реестре (см. §3.5). Пока закрепляем **базу** вручную по консенсусу; **пересортировка по данным** (в т.ч. телеметрия) — **отложенная** идея, после стабилизации реестра и палитры. |
| 30 | |
| 31 | --- |
| 32 | |
| 33 | ## 3. Лексика и синтаксис (v1) |
| 34 | |
| 35 | ### 3.1. Префикс namespace |
| 36 | |
| 37 | - **`c:`** — единственный вход в режим melody в строке палитры (регистр: **`c`** латинская нижняя; в v1 не допускается `C:` как синоним без отдельного решения). |
| 38 | |
| 39 | ### 3.2. Токены после префикса: domain → object → intent |
| 40 | |
| 41 | **Базовая ментальная модель** (канон для проектирования alias): |
| 42 | |
| 43 | | Слот | Смысл | Роль | |
| 44 | |------|--------|------| |
| 45 | | **D** | **domain** | Подсистема или крупная область (Git, Chat, Build, …) | |
| 46 | | **O** | **object** | Сущность внутри домена (topic, submodule, …); иногда **неявна** | |
| 47 | | **I** | **intent** | Действие или тип запроса (create, show, test, …) | |
| 48 | |
| 49 | **Полная форма** — три буквы подряд **`DOI`**, без разделителей: первая = domain, вторая = object, третья = intent. |
| 50 | |
| 51 | **Домен первым (намерение), не слой «Pages».** Первая буква хвоста кодирует **подсистему / зону заботы** пользователя: **c**hat, **e**nvironment (готовность), **t**erminal, **g**it, **b**uild, … — «хочу в чат», «хочу readiness», «хочу терминал». Искусственный префикс **P** = «Pages» для всех переходов во вторичный контур (**`pcs`**, **`pes`**, …) **не** используется: он описывает топологию IDE, а не намерение. Показ страницы внутри домена кодируется в слотах **O/I** (например **`cps`** = Chat → Page → Show, а не Pages → Chat → Show). *Замечание:* в таблице «семейств» одной буквы (ADR 0060) **e** = Editor; в **трёхбуквенном** DOI вроде **`ers`** (Environment → Readiness → Show) смысл задаёт **целиком** зарегистрированная мнемоника, а не первая буква по отдельности. |
| 52 | |
| 53 | Примеры: |
| 54 | |
| 55 | | Хвост | Разбор | Human title (ориентир) | |
| 56 | |-------|--------|-------------------------| |
| 57 | | **`ctc`** | **c**hat + **t**opic + **c**reate | Chat Topic Create | |
| 58 | | **`gs`** | **g**it + *(object не назван)* + **s**tatus | Git Status — естественное сокращение: репозиторий как контекст уже дан | |
| 59 | |
| 60 | **Сжатые формы (2 буквы):** допустимы, когда **object очевиден** из домена и привычной практики — и/или когда команда **высокочастотная** (§3.5). Реестр может хранить **синонимы** (длинная и короткая форма одной команды). |
| 61 | |
| 62 | **Обсуждаемое единообразие для глаголов:** для операций «показать / прочитать» можно завести в слоте **I** букву **`s` = Show** (read-only обзор), чтобы однотипно с **`c` = Create** и т.д. Тогда часть команд осознанно становится трёхбуквенной, например **`g?s`** с явным средним слотом — либо оставить **`gs`** как устоявшийся короткий канон для Git Status. Окончательное правило — **не зафиксировано**; см. §10. |
| 63 | |
| 64 | **Четвёртая и далее буквы:** уточнение, подкоманда или снятие коллизии — по реестру (§6). |
| 65 | |
| 66 | ### 3.3. Регистр |
| 67 | |
| 68 | - В v1 токены **case-insensitive** для сопоставления с реестром (`c: GS` ≡ `c: gs`), отображение в UI — по канону реестра (обычно lower). |
| 69 | |
| 70 | ### 3.4. Пробелы |
| 71 | |
| 72 | - Пробелы **после** `c:` до первого значимого символа хвоста допускаются (`c: gs`) — нормализуются к `c:gs` при разборе. |
| 73 | - Пробелы **внутри** хвоста в v1 **не** являются разделителями токенов (всё одна строка-мнемоника, если не введён другой режим в будущей версии языка). |
| 74 | |
| 75 | ### 3.5. Частота использования и длина alias (аналогия с кодами Хаффмана) |
| 76 | |
| 77 | Идея **префиксных кодов** (у Д. А. Хаффмана и в родственных схемах): символы с **большей вероятностью** получают **более короткие** коды — так минимизируется средняя длина сообщения. В IML «вероятность» заменяется на **ожидаемую частоту** команды в типичном дне разработчика: то, что дергают **постоянно**, должно набираться **двумя буквами**, реже — **три и более**, редкое — длинный хвост или только human title / `command_id`. |
| 78 | |
| 79 | **Оси с высоким трафиком** (ориентир, не жёсткий закон): **Git**, **сборка**, **отладка**, **тесты**, **запуск**, **чат** (страница Chat, экспорт, ветка) — первыми получают короткие мнемоники в реестре. |
| 80 | |
| 81 | **Иллюстративный набор** (конкретные буквы — в [0060 §11](adr/0060-keyboard-chord-stack-fms-tactical-strategic.md) и в `IdeCommands`; таблица согласована с частотным принципом): |
| 82 | |
| 83 | | Хвост (без `c:`) | Смысл | |
| 84 | |------------------|--------| |
| 85 | | `br` | Build → Run | |
| 86 | | `bt` | Build → Test | |
| 87 | | `da` | Debug → Attach | |
| 88 | | `dl` | Debug → Launch (`debug_launch`) | |
| 89 | | `dc` | Debug → Continue | |
| 90 | | `dn` | Debug → **next** (шаг с обходом, `debug_step_over`) | |
| 91 | | `di` | Debug → **into** (шаг с заходом, `debug_step_into`) | |
| 92 | | `df` | Debug → **finish** (шаг с выходом из кадра, `debug_step_out`) | |
| 93 | | `dx` | Debug → e**X**it / остановить сессию (`debug_stop`) | |
| 94 | | `gs` | Git → Status | |
| 95 | | `gc` | Git → Commit | |
| 96 | | `gp` | Git → Push | |
| 97 | | `gm` | Git → Merge | |
| 98 | | `gsu` | Git → Submodules *(трёхбуквенное — реже, чем merge/push; освобождает `gm` под merge)* | |
| 99 | | `so` | Solution → Open (диалог выбора .sln / .slnx) | |
| 100 | | `cps` | Chat → Page → Show (страница чата Mfd, `show_chat_page`) | |
| 101 | | `cs` | Chat → Send — отправить **текущий черновик** в поле ввода как сообщение user (`send_chat` без `message`; если поле пусто — команда не выполняется) | |
| 102 | | `cex` | Chat → экспорт в читаемый Markdown (`chat_export_readable`, без write_file по умолчанию) | |
| 103 | | `ctf` | Chat → Thread → Fork (`fork_chat_thread`, без parent; DOI, см. ADR 0060 §11) | |
| 104 | | `ers` | Environment → Readiness → Show (`show_environment_readiness_page`) | |
| 105 | | `ts` | Terminal → Show (`show_terminal_panel`) | |
| 106 | |
| 107 | Единый каталог intent в поставке — **`IntentMelody/intent-catalog.toml`** (встроенный ресурс + оверлей рядом с exe, как `Hotkeys/hotkeys.toml`; устаревшее имя файла: `intent-melody-aliases.toml`). |
| 108 | |
| 109 | **Сейчас:** короткие коды задаются **реестром и ревью** (качественный консенсус по Git / build / debug / test), без сбора частот из продукта. |
| 110 | |
| 111 | **Отложено:** автоматическая **перераздача** alias по измеренной частоте (локальная аналитика, opt-in сеть и т.д.) — вернуться после того, как **база** IML, палитры и `command_id` будут в стабильном минимуме; любая миграция alias — с заметкой в release notes и при необходимости дублированием старых alias на переходный период. |
| 112 | |
| 113 | --- |
| 114 | |
| 115 | ## 4. Грамматика (EBNF, черновик v1) |
| 116 | |
| 117 | Нотация для документации; парсер в IDE может быть проще (regex + lookup). |
| 118 | |
| 119 | ```ebnf |
| 120 | (* IML строка в палитре *) |
| 121 | iml_line ::= "c:" iml_tail ; |
| 122 | |
| 123 | iml_tail ::= ws_opt mnemonic_body ws_opt; |
| 124 | mnemonic_body ::= letter { letter | digit } ; (* минимум 2 символа; для новых команд предпочтительна форма DOI (§3.2), для частых — короткий alias по §3.5 *) |
| 125 | |
| 126 | letter ::= "a" | … | "z" | "A" | … | "Z" ; |
| 127 | digit ::= "0" | … | "9" ; |
| 128 | ws_opt ::= { " " | "\t" } ; |
| 129 | ``` |
| 130 | |
| 131 | **Примечание:** в v1 **нет** явного разделителя между D/O/I — тело целиком ключ в таблице alias → `command_id`. Семантика **domain → object → intent** задаётся **соглашением реестра и документации**, не парсером скобок. |
| 132 | |
| 133 | --- |
| 134 | |
| 135 | ## 5. Семантика |
| 136 | |
| 137 | 1. Разбор `iml_line` → **нормализованный хвост** (например `gs` или `ctc`). |
| 138 | 2. Поиск в **реестре melody alias** → ровно один **`command_id`** или **неоднозначность** / **отсутствие**. |
| 139 | 3. Исполнение — тот же путь, что для выбора команды из списка палитры: **dispatch по `command_id`**, без прямой адресации контролов. |
| 140 | |
| 141 | **Инвариант:** IML **никогда** не означает «нажать эти физические клавиши» — только **выбор команды**. |
| 142 | |
| 143 | --- |
| 144 | |
| 145 | ## 6. Реестр, конфликты, расширение |
| 146 | |
| 147 | Файл **IntentMelody/intent-catalog.toml** — канонический **command-first каталог** (`intent_catalog_schema_version = 1`; ключ версии **файла**, не «IML v2»). |
| 148 | |
| 149 | **IML v2** (смысл языка, [ADR 0109](adr/0109-declarative-parametric-melody-catalog-toml-and-code-binders.md)) — надстройка над IML v1: тот же wire `c:…`, но **`shape`**, **`tail_signature`**, **`[[tail_wire_class]]`**, детерминированная сборка args; параметрические корни (`eld`, `els`, `wai-url`, …) уже живут в этом каталоге. Отдельного `intent_catalog_schema_version = 2` для этого **нет** — это не версия языка. |
| 150 | |
| 151 | **Раскладка TOML** (читаемость, без смены номера схемы): |
| 152 | |
| 153 | - Якорь: **`command_id`** на `[[command]]`. |
| 154 | - **Melody** (0–1): поля **`melody_*`** на `[[command]]` или legacy **`[command.melody]`**. |
| 155 | - **Slash** (0..N): **`[[command.form.slash]]`** (или legacy **`[[command.slash]]`**); args — **`[command.form.slash.args]`** (`page`, `surface`). |
| 156 | - **`slash_group`**, **`enabled`**, секции-комментарии, cookbook в шапке файла. |
| 157 | |
| 158 | При необходимости **`[[tail_wire_class]]`** (см. также [ADR 0119](adr/0119-chat-slash-commands-intercom-surface.md)). |
| 159 | |
| 160 | **Slash-паритет (параметрика каталога):** для каждой команды с `melody_shape = parametric` — curated slash-путь и хвост по `wire_class` (редактор: `/editor line select|delete …`; портал: `/portal open [url]`). Сборка args — те же binders, что у `c:` — [ADR 0124](adr/0124-slash-parametric-editor-line-commands.md). |
| 161 | |
| 162 | **Slash workspace/file:** `/file open`, `/solution new`, динамические подсказки по файлам solution — [ADR 0125](adr/0125-slash-workspace-file-commands-and-dynamic-completion.md) (ортогонально параметрике 0124). |
| 163 | |
| 164 | В **`tail_signature`** для числовых слотов: **`:int`** — обобщённое целое; **`:ln`** или **`:linenumber`** — номер строки редактора (**1-based**, inclusive-диапазон как в продуктовой семантике диапазона строк). Загрузчик и разбор хвоста учитывают оба вида; для диапазонов строк в каталоге предпочтительно **`ln`**. |
| 165 | |
| 166 | Правила совпадают с [0060 §11](adr/0060-keyboard-chord-stack-fms-tactical-strategic.md#adr0060-p11): |
| 167 | |
| 168 | - Один alias в workspace → один `command_id`. |
| 169 | - Заголовок и `command_id` остаются **всегда** валидными путями поиска. |
| 170 | - При конфликте: уточнение третьей буквой, ветвление в реестре или пометка alias как invalid до разруливания. |
| 171 | |
| 172 | Слот **D (domain):** стартовый набор букв согласован с «семействами» в [0060 §11](adr/0060-keyboard-chord-stack-fms-tactical-strategic.md#adr0060-p11) (g/b/d/r/e/m/…); для **чата** и topic-навигации — отдельные соглашения по [0072](adr/0072-chat-topic-cards-intent-melody-keyboard-contract.md). Буквы слотов **O** и **I** — в реестре; типичные **I**: `c` create, `s` show (обсуждается), `t` test, и т.д. |
| 173 | |
| 174 | --- |
| 175 | |
| 176 | ## 7. Связь с физическим аккордом (CascadeChord) |
| 177 | |
| 178 | - **Ментальная модель:** те же буквы, что в хвосте IML, идут **после** префикса CascadeChord: `c: gs` ↔ **`Ctrl+K` → `G` → `S`**; `c: ctc` ↔ **`Ctrl+K` → `C` → `T` → `C`** (последовательность шагов — как в [0060](adr/0060-keyboard-chord-stack-fms-tactical-strategic.md); таймауты и overlay учитывают длину цепочки). |
| 179 | - **Реализация:** разные конвейеры ввода (текст палитры vs машина состояний аккорда), **один** `command_id`. |
| 180 | - Детали таймаута, Esc, overlay — [0060 §5–§6](adr/0060-keyboard-chord-stack-fms-tactical-strategic.md). |
| 181 | |
| 182 | --- |
| 183 | |
| 184 | ## 8. Почему это не «лечит» модификаторы напрямую, но снимает класс проблем |
| 185 | |
| 186 | **Проблема:** глобальные жесты вида **Ctrl+Shift+буква** проходят через цепочку **ОС → хост → фокус → IME/редактор**, и в части сценариев **буква** не доходит до приложения как ожидается (Avalonia и не только). |
| 187 | |
| 188 | **IML в палитре:** пользователь вводит **`c:`** и символы **без** удержания сложных модификаторов в одном системном chord; ввод идёт в **контроллер строки поиска**, где семантика — **текст**, а не `KeyGesture` с модификаторами на уровне окна. |
| 189 | То же **намерение** можно вызвать **аккордом** пошагово (префикс → буквы), что снова **не требует** одного атомарного `Ctrl+Shift+O`. |
| 190 | |
| 191 | Итог: **не замена** глобальных хоткеев, а **предпочтительный канон** для команд, где платформенная доставка chord нестабильна; **прямой** хоткей при необходимости остаётся в `hotkeys.toml` с другой, более доставляемой комбинацией. |
| 192 | |
| 193 | --- |
| 194 | |
| 195 | ## 9. Не-цели v1 |
| 196 | |
| 197 | - Полноценный DSL для скриптов (`c: pipe` / `c: $(…)`). |
| 198 | - Локализация мнемоник под язык UI (alias **developer-first**, EN-буквы; отдельное обсуждение). |
| 199 | - Замена **human title** и `command_id` в поиске. |
| 200 | |
| 201 | --- |
| 202 | |
| 203 | ## 10. Открытые вопросы (для обсуждения) |
| 204 | |
| 205 | 1. **Слот I и буква `s` (Show):** для высокочастотных команд **§3.5** уже оправдывает короткий `gs` без трёхбуквенного «формального» DOI; остаётся вопрос, нужен ли **явный** третий слот для редких read-команд внутри одного домена. |
| 206 | 2. **Явный разделитель** между D/O/I в будущих версиях (`c: g.s` vs `c: gs`) — нужен ли для читаемости или вреден для скорости? |
| 207 | 3. **Числовые** хвосты (`c: g1`) — для дискретных подкоманд или только буквы? |
| 208 | 4. **Конфликт с** вводом `c:` как начала **другого** запроса — только внутри палитры или глобальный shortcut на палитру с префиксом? |
| 209 | 5. **Паритет отображения:** всегда ли показывать тройку title / `c:` alias / id в одной строке результата ([0060](adr/0060-keyboard-chord-stack-fms-tactical-strategic.md))? |
| 210 | 6. **Chat / topic:** закрепить **`c`** как domain для chat и цепочки вида **`ct*`** (topic + intent), как в **`ctc`**, и таблицу букв для topic-navigation intents ([0072](adr/0072-chat-topic-cards-intent-melody-keyboard-contract.md)) — отдельным проходом по реестру. |
| 211 | |
| 212 | --- |
| 213 | |
| 214 | ## 11. История и нормативность |
| 215 | |
| 216 | Нормативный источник по продукту — **ADR 0060 §11** и реестр команд; этот документ **уточняет** грамматику и мотивацию. Детали реализации парсера палитры — в коде; при расхождении приоритет у ADR и реестра, затем обновление этого файла. |
| 217 | |