Архитектура¶
Общая форма¶
Neovim bugsaur (один процесс) адаптер программа
┌────────┐ IPC ┌─────────────────────────────┐ DAP ┌─────────┐ ┌─────────┐
│ Lua │◄───────►│ nvim-ipc → debugger-core │◄──────►│ dlv │──►│ ваш │
│ source │ Unix │ ↕ │ TCP / │ codelldb│ │ код │
│frontend│ сокет │ debugger-ui │ stdio │ debugpy │ │ │
└────────┘ └─────────────────────────────┘ └─────────┘ └─────────┘
Всё внутри средней коробки — один процесс. Окно не отдельная программа, а редактора в пути отладки нет вовсе.
Кто чем владеет¶
| Владелец | Чем владеет |
|---|---|
debugger-core |
состоянием сессии — единственный источник истины о том, как сейчас обстоят дела |
dap-client |
соединением с адаптером и запросами в полёте |
| адаптер | отлаживаемой программой и всем знанием о языке |
| редактор | набором точек останова файла и показом исходника |
debugger-ui |
тем, как состояние отображается, и ничем — тем, каково оно |
Отсюда два правила, а вместе с ними и большая часть структуры кода.
Состояние решает только debugger-core. Интерфейс рисует проекцию, редактор
шлёт намерения. Ни тот, ни другой не меняют модель напрямую.
Язык интерпретирует только адаптер. Bugsaur никогда не разбирает значение, не угадывает тип и не переписывает тело запроса. Там, где специфики адаптера не избежать, она живёт в каталоге адаптеров как данные, а не как ветвление в общем коде.
Цикл команд и событий¶
debugger-core — это редьюсер, а не контроллер:
команда → reduce(состояние, команда) → эффекты
событие → reduce(состояние, событие) → новое состояние + эффекты
- Команды — это намерения: продолжить, шагнуть, вычислить, развернуть переменную. Они приходят от интерфейса или от редактора.
- События — это факты: адаптер остановился, появился поток, запрос ответил.
- Эффекты — что должно произойти дальше: отправить DAP-запрос, попросить фронтенд открыть файл, поднять окно.
Редукция чистая, и именно поэтому модель состояния тестируется без адаптера,
редактора и окна — см. crates/debugger-core/tests/.
Поколения остановок¶
У каждой остановки есть номер поколения, и это механизм, который не пускает на экран устаревшие данные.
Как только программа сдвинулась, поколение растёт. Ответы, пришедшие позже — страница переменных, запрошенная до шага, или слишком долгий scope, — отбрасываются, а не показываются. Значение с прошлой остановки рядом с текущей строкой было бы хуже, чем отсутствие значения.
Тем же поколением ограничен кэш переменных: поэтому разворачивание дерева дёшево внутри одной остановки и начинается заново после следующей.
Фазы сессии¶
Фаза building существует потому, что часть программ Bugsaur компилирует сам, до
старта адаптера — измерения, которые к этому привели, есть в
Языки → Go. Неудачная сборка до адаптера не доходит.
Окно — это представление¶
debugger-ui построен на egui и никакой властью не обладает. Он рисует
проекцию состояния — уплощённый виртуализированный список видимых строк — и
превращает ввод в команды.
Два следствия, заметных пользователю:
- перетащенные мышью панели не сохраняются: раскладка строится из конфигурации на каждый запуск;
- точку останова нельзя снять из окна, потому что владелец у неё — редактор.
Где читать дальше¶
| Тема | Страница |
|---|---|
| Слой протокола | Модель DAP |
| Граница с редактором | IPC |
| Почему принято именно такое решение | ADR |