| 1 | # ADR 0081: Параметрические Intent Melody — диапазоны строк редактора (`:start:end`) |
| 2 | |
| 3 | **Статус:** Accepted · Implemented |
| 4 | **Дата:** 2026-04-20 |
| 5 | ## Связанные ADR |
| 6 | |
| 7 | | ADR | Роль | |
| 8 | |-----|------| |
| 9 | | [0060](0060-keyboard-chord-stack-fms-tactical-strategic.md) | Command Melody, CascadeChord, keyboard-first | |
| 10 | | [0030](0030-command-ids-hotkeys-and-ui-registry-layers.md) | `command_id` и слои UI | |
| 11 | | [0013](0013-command-surface-and-discoverability.md) | палитра и discoverability | |
| 12 | | [0070](0070-command-palette-direct-overlay-surface.md) | палитра как overlay | |
| 13 | | [0079](0079-ide-display-system-ids-overlay-pipeline.md) | IDS — композиция оверлея ввода | |
| 14 | | [0072](0072-chat-topic-cards-intent-melody-keyboard-contract.md) | intent-first входы в домене чата | |
| 15 | | [0075](0075-ui-topic-index-and-mfd-page-conventions.md) | зоны внимания / MFD | |
| 16 | | [0039](0039-workspace-navigation-affordances.md) | Навигация по workspace — несколько представлений и «текущий файл + связанные» | |
| 17 | | [0080](0080-intercom-naming-and-multi-party-channel-model.md#adr0080-future-modalities) | якоря на код — смежная тема, не дублирует этот ADR | |
| 18 | | [0110](0110-roslyn-refactor-intent-melody-bridge.md) | Рефакторинги Roslyn по диапазону — мост Intent Melody / IDE и Roslyn MCP | |
| 19 | |
| 20 | ## Резюме |
| 21 | |
| 22 | - Параметрические **Intent Melody:** суффикс `:startLine:endLine` для операций над текстом. |
| 23 | - Валидация диапазона; мост к Roslyn — [0110](0110-roslyn-refactor-intent-melody-bridge.md). |
| 24 | |
| 25 | |
| 26 | ### Вне ADR |
| 27 | |
| 28 | | Документ | Роль | |
| 29 | |----------|------| |
| 30 | | [intent-melody-language-v1.md](../intent-melody-language-v1.md) | IML v1: грамматика `c:` и реестр alias | |
| 31 | | [`IntentMelody/intent-melody-aliases.toml`](../../IntentMelody/intent-melody-aliases.toml) | оверлей alias → `command_id` | |
| 32 | | [Roslyn MCP](../../../roslyn-mcp/README.md) | Roslyn MCP | |
| 33 | |
| 34 | --- |
| 35 | ## Контекст |
| 36 | |
| 37 | В IML v1 хвост после `c:` — это **мнемоника**, резолвящаяся в **`command_id`** через реестр ([`intent-melody-aliases.toml`](../../IntentMelody/intent-melody-aliases.toml), [ADR 0060 §11](0060-keyboard-chord-stack-fms-tactical-strategic.md#adr0060-p11)). Для команд уровня «Git status» или «открыть страницу Chat» этого достаточно: контекст задаётся фокусом и текущим решением. |
| 38 | |
| 39 | Операции над **текстом активного редактора** (выделить диапазон строк, удалить диапазон, **Extract Method** и другие рефакторинги Roslyn по диапазону) принципиально требуют **параметра** — хотя бы **диапазон строк** — иначе одна и та же мнемоника неоднозначна или вынуждена опираться только на текущее выделение, что хуже для сценариев «знаю номера строк». |
| 40 | |
| 41 | --- |
| 42 | |
| 43 | ## Проблема |
| 44 | |
| 45 | 1. **Разрыв «намерение → команда»:** без параметров пользователь вынужден сначала выделить текст мышью/клавиатурой, затем вызывать команду; для power-user с номерами из лога/диффа это медленнее, чем **одна строка ввода** с диапазоном. |
| 46 | 2. **Паритет поверхностей:** если параметр доступен только через меню или отдельный диалог, страдает принцип **те же `command_id` и те же входы**, что палитра и Melody ([0060](0060-keyboard-chord-stack-fms-tactical-strategic.md), [0008](0008-mcp-contracts-and-testable-infrastructure.md)). |
| 47 | 3. **Ошибки ввода:** диапазон вне файла или `start > end` не должны приводить к **молчаливому** разрушительному эффекту или к правке не того фрагмента. |
| 48 | |
| 49 | --- |
| 50 | |
| 51 | ## Решение (предлагаемое) |
| 52 | |
| 53 | <a id="adr0081-p1"></a> |
| 54 | |
| 55 | ### 1. Суффикс диапазона строк |
| 56 | |
| 57 | После **зарегистрированного** короткого alias (корень мелодии без `c:` в терминах реестра) допускается **опциональный** суффикс вида **`:startLine:endLine`**: |
| 58 | |
| 59 | - **`startLine`**, **`endLine`** — целые числа, **1-based**, **включительно** (согласовано с номерами строк в редакторе и типичными сообщениями компилятора). |
| 60 | - Разделитель полей — **`:`**; парсер после матча базового alias **сначала** резолвит префикс в `command_id` / доменную операцию, затем, если хвост продолжается шаблоном `:digits:digits`, интерпретирует пару как диапазон строк. |
| 61 | |
| 62 | **Иллюстративные примеры** (финальные мнемоники и привязка к `command_id` — решение реестра и продукта, не жёстко зашитые в парсер): |
| 63 | |
| 64 | | Ввод (фрагмент после `c:`) | Намерение (ориентир) | |
| 65 | |---------------------------|----------------------| |
| 66 | | `els:5:15` | Editor → Line → Select строки 5–15 в активном документе | |
| 67 | | `eld:5:15` | Editor → Line → Delete в указанном диапазоне | |
| 68 | |
| 69 | Канон этой ADR-ветки: |
| 70 | |
| 71 | - Для операций над диапазоном строк использовать модель **Editor → Line** (`el*`), без legacy/синонимов `es*`. |
| 72 | - Семейство мелодий **Refactor → …** по диапазону (`rmx`, `rix`, …) и связка с Roslyn / **Roslyn MCP** (`roslyn_get_code_actions` / `roslyn_apply_code_action`) **не входят в обязательный минимум этого ADR** — см. [0110](0110-roslyn-refactor-intent-melody-bridge.md). |
| 73 | |
| 74 | Расширение **IML v1** в [`intent-melody-language-v1.md`](../intent-melody-language-v1.md) (новый подпункт про параметрический хвост) — **отдельным шагом** после стабилизации формата; до тех пор этот ADR — **норматив направления** для реализации и документации. |
| 75 | |
| 76 | <a id="adr0081-p2"></a> |
| 77 | |
| 78 | ### 2. Валидация и отказ |
| 79 | |
| 80 | - Диапазон **обязан** укладываться в текущую длину документа (в строках); при нарушении — **явная обратная связь** (строка состояния палитры, краткий annunciator в IDS — по [0079](0079-ide-display-system-ids-overlay-pipeline.md)), **без** применения деструктивного действия «как получится». |
| 81 | - Условие **`startLine <= endLine`**; иначе — тот же класс ошибки, что и выход за границы. |
| 82 | |
| 83 | <a id="adr0081-p3"></a> |
| 84 | |
| 85 | ### 3. Рефакторинги Roslyn (Extract Method и аналоги) |
| 86 | |
| 87 | Команды, которые в IDE уже ожидают **выделение** в редакторе (в т.ч. Roslyn: `roslyn_get_code_actions` с диапазоном для Extract method и аналогов), должны вести себя предсказуемо: |
| 88 | |
| 89 | - Если есть **непустое выделение** в активном документе — возможен **приоритет выделения** над числовым суффиксом (продуктовое правило: «явный жест побеждает») **или** однозначная политика «суффикс всегда задаёт диапазон» — **зафиксировать при реализации** и отразить в help. |
| 90 | - Если выделения нет — **синтетическое выделение** по строкам `startLine`–`endLine` (целые строки, включая переводы строк по принятому в редакторе правилу) перед вызовом того же пути, что и из UI. |
| 91 | |
| 92 | <a id="adr0081-p4"></a> |
| 93 | |
| 94 | ### 4. UX: discoverability и режим ввода |
| 95 | |
| 96 | - **Индикатор распознанной мелодии:** при активном **command mode** / вводе в палитре показывать краткий разбор: базовый alias + числовой диапазон (и при ошибке — причину). Цель — снизить ошибки «я думал, что ввёл другое» без обязательного длинного лога. |
| 97 | - **Chord vs только палитра:** открытый вопрос — разрешать ли параметрический хвост в **CascadeChord** (`Ctrl+K` → последовательность букв) или ограничить **палитрой** ради меньшего числа опечаток без превью. Решение — отдельно; этот ADR допускает оба варианта как реализации. |
| 98 | |
| 99 | --- |
| 100 | |
| 101 | ## Последствия |
| 102 | |
| 103 | - Расширение разборщика строки палитры / Melody и связки с VM: команды редактора, принимающие диапазон, получают **единый** контракт из IML, а не только из pointer. |
| 104 | - Реестр [`intent-melody-aliases.toml`](../../IntentMelody/intent-melody-aliases.toml) может ссылать **те же** `command_id`, что и без параметров; семантика «с параметром / без» — в обработчике команды или тонком адаптере. |
| 105 | - Документация MCP / `IdeCommands`: для соответствующих команд при необходимости уточняются **args** или параллельный путь «из палитры с диапазоном». |
| 106 | |
| 107 | --- |
| 108 | |
| 109 | ## Отклонённые альтернативы |
| 110 | |
| 111 | - **Только MCP с явными аргументами** — ломает keyboard-first и единую строку намерения в IDE для человека. |
| 112 | - **Только пробел как разделитель** (`5 15`) — конфликтует с направлением IML v1 «пробелы внутри хвоста не режут токены» ([§3.4](../intent-melody-language-v1.md#34-пробелы)); суффикс с **`:`** после полного матча alias воспроизводимее. |
| 113 | - **Привязка только к mouse / gutter** — не отменяется, но не заменяет параметрический ввод для пользователей без указателя на строке. |
| 114 | |
| 115 | --- |
| 116 | |
| 117 | ## Открытые вопросы |
| 118 | |
| 119 | 1. Ограничить параметрические формы **только палитрой** на первом релизе или сразу разрешить chord-ввод. |
| 120 | 2. Нужны ли в следующей итерации **столбцы** или **поддиапазоны внутри строки** — вынести за пределы минимального `:start:end` по строкам. |
| 121 | 3. Синхронизация с будущими **якорями на код** из [0080](0080-intercom-naming-and-multi-party-channel-model.md) (deep link): общий слой «диапазон в документе» или отдельные контракты. |
| 122 | |