Forge
markdowndeeb25a2
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
251. **Intent-first:** пользователь вводит **домен → объект → намерение** (см. §3.2), а не координаты UI. Допускается **сжатая** форма из двух букв, когда **объект** подразумевается контекстом.
262. **Паритет поверхностей:** тот же смысл доступен из палитры (строка), **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).
273. **Стабильность:** при смене формулировки в UI alias может оставаться неизменным.
284. **Обход хрупкости глобальных жестов:** ввод в палитре **не зависит** от того, что ОС/IME/фокус доставили одну **сложную** комбинацию модификаторов + букву в одном событии (см. §8).
295. **Частота → длина (эвристика):** чем **типичнее** команда для рабочего дня разработчика, тем **короче** разумный 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 строка в палитре *)
121iml_line ::= "c:" iml_tail ;
122
123iml_tail ::= ws_opt mnemonic_body ws_opt;
124mnemonic_body ::= letter { letter | digit } ; (* минимум 2 символа; для новых команд предпочтительна форма DOI (§3.2), для частых — короткий alias по §3.5 *)
125
126letter ::= "a" | … | "z" | "A" | … | "Z" ;
127digit ::= "0" | … | "9" ;
128ws_opt ::= { " " | "\t" } ;
129```
130
131**Примечание:** в v1 **нет** явного разделителя между D/O/I — тело целиком ключ в таблице alias → `command_id`. Семантика **domain → object → intent** задаётся **соглашением реестра и документации**, не парсером скобок.
132
133---
134
135## 5. Семантика
136
1371. Разбор `iml_line` → **нормализованный хвост** (например `gs` или `ctc`).
1382. Поиск в **реестре melody alias** → ровно один **`command_id`** или **неоднозначность** / **отсутствие**.
1393. Исполнение — тот же путь, что для выбора команды из списка палитры: **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
2051. **Слот I и буква `s` (Show):** для высокочастотных команд **§3.5** уже оправдывает короткий `gs` без трёхбуквенного «формального» DOI; остаётся вопрос, нужен ли **явный** третий слот для редких read-команд внутри одного домена.
2062. **Явный разделитель** между D/O/I в будущих версиях (`c: g.s` vs `c: gs`) — нужен ли для читаемости или вреден для скорости?
2073. **Числовые** хвосты (`c: g1`) — для дискретных подкоманд или только буквы?
2084. **Конфликт с** вводом `c:` как начала **другого** запроса — только внутри палитры или глобальный shortcut на палитру с префиксом?
2095. **Паритет отображения:** всегда ли показывать тройку title / `c:` alias / id в одной строке результата ([0060](adr/0060-keyboard-chord-stack-fms-tactical-strategic.md))?
2106. **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
View only · write via MCP/CIDE