# AGENTS.md `qode` — настольный редактор кода на GPUI (`gpui-kit`) с расширением поведения через Lua и клиентом LSP по stdio. Этот файл описывает архитектуру и принципы, которые нужно сохранять при изменениях. ## Модули | Путь | Ответственность | | --- | --- | | `src/main.rs` | Точка входа, окно, аргументы командной строки | | `src/constants.rs` | Константы окна, CLI и каталог сценариев | | `src/editor.rs` | Доменная модель: документы, вкладки, языки | | `src/api.rs` | `AppApi` / `PanelApi` / `TreeApi` / `ToolbarApi` — единственная поверхность управления | | `src/script.rs` | Lua-движок, `app`, `include`, `require` | | `src/keymap.rs` | `KeyBinding`, `KeyMap`, встроенные команды и Lua-обработчики | | `src/app.rs` | GPUI-вид, отрисовка, события, автодополнение | | `src/completion.rs` | Всплывающий список, `CaretPopup`, преобразования LSP-элементов | | `src/panel.rs` | `PanelState` и блоки панелей | | `src/toolbar.rs` | Состояние верхней панели: лейблы и кнопки | | `src/tree.rs` | Абстрактное дерево для панелей | | `src/icons.rs` | Каталог иконок Lucide | | `src/lsp.rs` | Менеджер LSP-серверов, JSON-RPC, файловый вотчер | | `DOCS.md`, `init.lua` | Пользовательская документация и пример конфигурации | ## Главные принципы ### 1. `AppApi` — центр приложения - Документы, вкладки, панели, дерево, окно, подсветка, LSP и привязки клавиш меняются только через `AppApi` (или `PanelApi` / `TreeApi`). - Состояние живёт в общих `Rc>` / `Arc`, чтобы UI, `AppApi` и Lua видели одни и те же объекты. Второй копии состояния быть не должно. - Команды окна складываются в очередь и применяются в начале кадра (`apply_window_commands`); UI и Lua не вызывают `Window` напрямую. - Если действие пользователя меняет состояние, оно выражается методом `AppApi`, а не логикой внутри обработчика UI. Отрисовка состояние только читает. - Исключение — системные кнопки окна внутри `gpui-kit::TitleBar`: их поведение принадлежит библиотеке. ### 2. Lua повторяет возможности API - Публичные методы `impl AppApi` с `#[mlua::userdata_impl]` доступны как `app:method(...)`. Добавляя возможность, сразу добавляйте и Lua-метод. - Имена — `snake_case`; вкладки и индексы нумеруются с нуля; панели — `app.left_panel`, `app.right_panel`, `app.bottom_panel`. - Для методов, которые не должны попадать в Lua, используется `#[lua(skip)]`. Для generic-методов добавляется тонкая не-generic Lua-обёртка. - `DOCS.md` и комментарии в `init.lua` обновляются в том же изменении, что и публичный API. Документация описывает фактическое поведение, без «запланированных» методов. ### 3. Клавиатура — только через `KeyMap` - Встроенные привязки (`Ctrl/Cmd+S`, `Ctrl/Cmd+Space`, навигация по списку автодополнения) регистрируются в `KeyMap` и могут быть заменены или удалены из Lua через `app:map_key` / `app:map_completion_key`. - `KeyMap` имеет два слоя: глобальный и `completion`. Обработчик может быть Lua-функцией или встроенной командой. - Перехватчик клавиш выполняется раньше действий редактора и используется только для слоя автодополнения; глобальные привязки обрабатываются на корне вида. Этот порядок менять нельзя. - Текстовый ввод редактора — не привязка клавиши. ### 4. Модель отделена от GPUI - `editor.rs`, `panel.rs` и `tree.rs` не знают о `Window` и `Context`. - Вид переносит изменения модели в виджет по `Workspace::revision`; набор текста в редакторе ревизию не трогает, чтобы не сбрасывать курсор. - Инвариант `Workspace`: открыт хотя бы один документ. Поэтому `active()` возвращает документ без `Option`. - Встроенный старт — одна пустая вкладка. Примеры и демонстрационные документы не должны попадать в код приложения; `init.lua` — единственное место для примеров. ### 5. LSP работает в фоне - `LspManager` общий (`Arc`) для вида, API и фоновых задач. - Процессы, чтение stdout/stderr и файловый вотчер живут в отдельных потоках; ответы приходят через каналы и ожидаются в `background_executor`, а не в кадре UI. - Какие серверы запускать, решает Lua; менеджер отвечает только за жизненный цикл, JSON-RPC и синхронизацию документов. ## Соглашения - Код, комментарии и пользовательская документация — на русском. - Публичные элементы Rust документируются `///`. - Новые зависимости добавляются только при реальной необходимости; сначала используются возможности `gpui-kit`, `mlua` и уже подключённых крейтов. - Изменения должны быть локальными и в стиле окружающего кода. Не добавляйте параллельные пути управления и не оставляйте мёртвый код. ## Проверка Перед завершением изменения: ```sh cargo fmt cargo test cargo build ``` Если какую-то команду выполнить нельзя, это нужно явно указать в ответе.