Code Retype
Задумка:
Хочется сделать расширение для vscode которое по определенной конфигурации (файлы + интервалы строк) (надо проработать формат) даст тебе переписать код руками в этих местах.
Зачем: упросить понимание важных участков кода для понимания проекта и pull request'ов которые делают нейросети.
Переписывание кода требует большей концентрации и не позволяет по диагонали просматривать изменения.
Как это работает
В корне проекта лежит .retype.json со списком участков (файл + диапазоны строк).
Retype: Start Session открывает два редактора рядом:
- слева оригинал (read-only зеркало файла), нужный диапазон подсвечен, текущая строка выделена ярче;
- справа пустой редактор, в который вы перепечатываете участок строка за строкой. Подсветка синтаксиса, автоотступы и автозакрытие скобок работают как в обычном файле.
Пока вы печатаете, строки сравниваются с оригиналом:
- зелёная — совпала;
- без подсветки — ещё набирается (является префиксом ожидаемой строки);
- красная с волнистым подчёркиванием от первого расхождения — ошибка, при наведении показывается ожидаемая строка;
- совпавшие строки в оригинале слева приглушаются.
Пробелы по умолчанию не учитываются вообще: отступы, выравнивание и пробелы вокруг операторов можно ставить как удобно. return a+b; засчитывается за return a + b;. Строгость настраивается через retype.whitespace.
В конце строки работает жест двойного нажатия →:
- строка ещё не набрана — она допишется из оригинала (то же делает команда
Retype: Fill In Current Line);
- строка уже совпала и это последняя набранная строка — откроется следующая с отступом оригинала, Enter нажимать не нужно.
То есть четыре нажатия подряд дописывают строку и сразу переводят на новую. Первое нажатие в паре только взводит жест и показывает подсказку в статус-баре, на обычную навигацию стрелка не влияет.
Следующий символ, который осталось набрать, обведён рамкой в левом окне: сразу видно, где вы остановились. Пробелы и отступы пропускаются, подсвечивается ближайший непробельный символ, а когда строка дописана, рамка перескакивает на начало следующей. Позиция считается с учётом режима пробелов, поэтому работает и когда вы печатаете с другими отступами. Отключается через retype.highlightNextCharacter.
Левое окно само едет за курсором: и по вертикали, и по горизонтали. Длинную строку не нужно подкручивать полосой прокрутки, оригинал сдвигается вместе с набором и держит впереди ещё сорок символов. Отключается через retype.syncReferenceScroll.
Комментарий, который автор конфига оставил к участку, виден прямо у кода: он разложен курсивом по правому краю первых строк участка в левом окне и целиком показывается в подсказке при наведении на участок. Отключается через retype.showNotes.
Копирование из левого окна в правое разрешено: выделяете мышью, Ctrl+C, Ctrl+V справа. Пока в левом окне что-то выделено, подсветка участка убирается, иначе выделения не видно: VS Code рисует декорации поверх него. Прокрутка за курсором в это время тоже приостанавливается. Команда Retype: Copy Original Lines кладёт в буфер сразу весь текущий участок. Если хочется запретить себе вставку, включите retype.blockPaste: тогда Ctrl+V, Shift+Insert и многострочные вставки будут откатываться.
Когда все строки совпали, участок отмечается выполненным, всплывает предложение перейти к следующему. Прогресс сохраняется в workspace и привязан к содержимому кода: если участок в файле поменялся, его придётся набрать заново.
Реальные файлы проекта расширение никогда не изменяет: правый редактор живёт в памяти (схема retype:), левый доступен только для чтения.
Формат конфига
.retype.json (допускаются комментарии и висячие запятые, в редакторе есть валидация по схеме):
{
"targets": [
// Короткая форма: путь:диапазоны через запятую. Строки нумеруются с 1, границы включительно.
"src/parser.ts:12-40,55",
// Развёрнутая форма
{ "file": "src/lexer.ts", "lines": "1-30" },
{ "file": "src/vm.ts", "lines": ["100-140", "203"], "note": "горячий цикл интерпретатора" },
// длинный комментарий удобно писать массивом строк
{
"file": "src/orders.ts",
"lines": ["120-138"],
"note": [
"Что делает колбэк одного ордера: ошибка превращается в reject",
"с ErrorReason и признаком «статус неизвестен»"
]
},
// комментарии к конкретным строкам: ключ — номер строки в файле
{
"file": "src/orders.ts",
"lines": ["150-160", "171", "180-184"],
"notes": {
"150": "поиск пака по ecid, если нет — создаём",
"171": "ответ раскладывается по колбэкам каждого ордера",
"182": ["ошибка отправки: все контроллеры снимаются разом,", "иначе каждый уходит в PendingActive"]
}
}
]
}
Пути указываются относительно корня workspace.
Комментарии для того, кто будет перепечатывать участок, бывают двух видов:
note — комментарий ко всей записи. Он виден в списке Retype: Pick Target..., в подсказке при наведении на участок, а курсивом по правому краю кода — у первого диапазона записи. Если у записи несколько диапазонов, на остальных он не повторяется с начала, только в подсказке.
notes — комментарии, привязанные к строкам: объект «номер строки → текст». Каждый рисуется рядом со своей строкой и, если не помещается, продолжается на строках ниже — до следующего привязанного комментария или конца диапазона. Номер должен попадать в один из диапазонов записи, иначе конфиг не загрузится. Это удобно, когда одна запись покрывает несколько кусков файла и к каждому нужно своё пояснение.
Оба поля принимают строку или массив строк; массив превращается в многострочный комментарий. Комментарий относится к той записи, в которой написан, поэтому для разных note к одному файлу заводите отдельные записи.
Заполнять конфиг руками не обязательно:
Retype: Create Config from Git Diff — берёт добавленные строки из git diff (незакоммиченные изменения, последний коммит, текущая ветка против main/master, или произвольные аргументы вроде main...feature) и записывает их как участки. Это основной сценарий для ревью PR, написанных нейросетью. Lock-файлы, .min.js, .map, .svg и т.п. пропускаются (список — в настройке retype.gitDiffExclude). Если конфиг уже есть, предложит заменить или дополнить.
Retype: Add Selection to Config — выделите строки в любом файле проекта (или в левом окне с оригиналом), вызовите команду из палитры или контекстного меню, и диапазон допишется в конфиг. Вариант ... with Note... дополнительно спросит комментарий к участку.
Для агентов (Claude Code, Cursor и т.п.)
Конфиг — обычный JSON в корне проекта, поэтому агент может собрать его сам, без участия расширения: перечислить файлы и диапазоны, которые он считает ключевыми в своём PR. Файлов может быть сколько угодно, у каждого несколько диапазонов. Если .retype.json закоммитить вместе с PR, ревьюер получит готовый маршрут.
Готовый фрагмент для CLAUDE.md / системного промпта:
Когда заканчиваешь PR, создай или обнови .retype.json в корне репозитория.
Формат: {"targets": [{"file": "<путь от корня>", "lines": ["<от>-<до>", ...], "note": "<почему это важно>",
"notes": {"<номер строки>": "<что важно в этой строке>"}}]}.
Поле note — комментарий ревьюеру ко всей записи, его видно рядом с кодом у первого диапазона.
Поле notes — комментарии к конкретным строкам, номер строки должен входить в lines; используй их,
когда у записи несколько диапазонов. Длинный комментарий пиши массивом строк.
Если к разным участкам одного файла нужны разные note, заводи отдельные записи.
Строки нумеруются с 1, границы включительно. Включи только участки, которые ревьюеру
стоит понять по-настоящему: новую логику, инварианты, обработку ошибок. Не включай
тесты-заглушки, импорты и сгенерированный код. Суммарно не больше ~150 строк.
Альтернатива без участия агента: Retype: Create Config from Git Diff соберёт конфиг из всех добавленных строк PR, а лишнее можно вычистить руками.
Команды
| Команда |
Что делает |
Retype: Start Session |
Загружает конфиг и открывает первый незавершённый участок |
Retype: Next Target / Previous Target |
Переход между участками (кнопки есть и в заголовке правого редактора) |
Retype: Pick Target... |
Список всех участков с отметками о выполнении; открывается и по клику на статус-бар |
Retype: Fill In Current Line |
Дописывает текущую строку из оригинала (то же, что двойное нажатие →) |
Retype: Stop Session |
Закрывает окна сессии |
Retype: Add Selection to Config |
Добавляет выделенные строки в конфиг |
Retype: Add Selection to Config with Note... |
То же, но сначала спрашивает комментарий к участку |
Retype: Copy Original Lines |
Кладёт текст текущего участка в буфер обмена |
Retype: Create Config from Git Diff |
Генерирует конфиг из diff |
Retype: Open Config |
Открывает .retype.json (создаёт шаблон, если его нет) |
Retype: Reset Progress |
Забывает выполненные участки и набранный текст |
Настройки
| Настройка |
По умолчанию |
Смысл |
retype.configPath |
.retype.json |
Путь к конфигу относительно корня workspace |
retype.whitespace |
ignore |
Строгость к пробелам: ignore — не учитывать совсем, collapse — игнорировать отступы и схлопывать пробелы, trim — игнорировать только пробелы в конце строки, strict — учитывать всё |
retype.completeLineOnDoubleRight |
true |
Двойное нажатие → в конце незавершённой строки дописывает её из оригинала |
retype.showNotes |
true |
Показывать комментарий к участку на полях левого окна |
retype.highlightNextCharacter |
true |
Обводить в левом окне следующий непробельный символ, который осталось набрать |
retype.syncReferenceScroll |
true |
Держать левое окно на строке и колонке, которые набираются, чтобы длинные строки не приходилось прокручивать руками |
retype.referenceLookahead |
40 |
Сколько символов после курсора остаётся видно в левом окне при проходе по длинной строке |
retype.blockPaste |
false |
Блокировать вставку и многострочные вставки в редакторе набора |
retype.maxInsertLength |
30 |
Одиночная вставка длиннее этого числа символов считается пастой и откатывается |
retype.gitDiffExclude |
lock-файлы, .min.js, .map, … |
Суффиксы путей, которые пропускаются при генерации из diff |
Сборка и установка
С установленным Node.js:
npm install
npm run compile
npx @vscode/vsce package # -> code-retype-0.6.1.vsix
code --install-extension code-retype-0.6.1.vsix
Без Node.js (используется Electron из самого VS Code и Python для упаковки; зависимости из node_modules уже должны быть на месте):
scripts/build.sh # компиляция tsc через VS Code-овский Electron
scripts/package.py # -> code-retype-0.6.1.vsix
code --install-extension code-retype-0.6.1.vsix
Для разработки: откройте папку в VS Code и нажмите F5 (Run Extension).
Сквозной тест (scripts/smoke.sh) поднимает отдельный экземпляр VS Code с расширением и прогоняет сценарий из test/smoke/index.js: старт сессии, откат вставки, набор строк с ошибкой и исправлением, завершение участка, переходы, остановка. Юнит-тесты чистых модулей лежат рядом в test/unit.js (запуск: node test/unit.js или через scripts/build.sh-подобный трюк с Electron).
Публикация
Сейчас расширение живёт в .vsix и ставится командой code --install-extension. Чтобы оно появилось у всех через Extensions в VS Code:
- Завести publisher на https://marketplace.visualstudio.com/manage (нужен аккаунт Microsoft и Personal Access Token в Azure DevOps с правом Marketplace → Manage).
- В
package.json выставить publisher равным id этого publisher'a и добавить repository (ссылку на git-репозиторий), по желанию icon.
npx @vscode/vsce login <publisher> и npx @vscode/vsce publish (нужен Node.js). Через несколько минут расширение доступно всем по id <publisher>.code-retype.
- Для VSCodium, Cursor и подобных дополнительно опубликовать на https://open-vsx.org (
npx ovsx publish).
После публикации в проектах можно добавить в .vscode/extensions.json рекомендацию "<publisher>.code-retype", и VS Code сам предложит установку всем участникам. Без Marketplace остаётся вариант выкладывать .vsix в GitHub Releases и ставить руками.
Структура
src/configFormat.ts — формат конфига, парсинг JSONC, слияние диапазонов (без зависимостей от VS Code)
src/compare.ts — сравнение набранных строк с оригиналом
src/gitDiff.ts — запуск git diff -U0 и разбор hunk-заголовков
src/notes.ts — раскладка комментария по полям левого окна
src/memfs.ts — in-memory файловая система для редактора набора
src/session.ts — сессия: открытие пары редакторов, декорации, блокировка вставки, прогресс
src/extension.ts — команды
schemas/retype.schema.json — JSON-схема конфига
media/icon.svg — исходник иконки, media/icon.png рендерится из него через rsvg-convert -w 128 -h 128