Skip to content

Lua domain model ru

Ilia Maslakov edited this page Aug 22, 2026 · 3 revisions

Доменная модель Lua-расширений MC

1. Архитектурный обзор (Принципы)

В основе архитектуры лежит жесткое разделение ответственности между политикой (Lua) и механизмом (MC Core).

  • Единый Runtime: Lua в MC — это одна подсистема, а не набор отдельных плагинов. Она загружает пакеты, изолирует их от внутренних структур MC и предоставляет несколько независимых предметных API.
  • Архитектурная граница:
    1. Lua-пакет: Определяет поведение, преобразования и содержимое.
    2. Runtime adapter: Проверяет Lua-значения, переводит их в стабильный C ABI.
    3. Host services: Выполняют разрешённые операции MC.
    4. MC Core: Владеет виджетами, памятью, жизненным циклом, отрисовкой.
  • Правило нулевого доступа: Lua никогда не получает прямых указателей на внутренние структуры MC (WPanel, WEdit, буферы, widget ID, VFS-объекты и т.д.). Взаимодействие идет только через Opaque handles и immutable snapshots.

Иерархическая схема слоев

flowchart TD
    %% Nodes
    P["1. Lua Package"]
    RA["2. Lua Runtime Adapter / mc-lua"]
    HS["3. MC Host Services"]
    MC_W["Core: Editor, Panels, Viewer, Diff Viewer"]
    MC_M["Core: Dialogs, Processes, Keymap, Events, Lifecycle"]

    %% Edges
    P <-->|"Domain API calls and Lua callbacks"| RA
    RA <-->|"Validated, typed runtime ABI"| HS
    HS <-->|"Host operations and callbacks"| MC_W
    HS <-->|"Host operations and events"| MC_M
Loading

Стрелки двунаправленные: Lua вызывает host services через runtime adapter, а MC доставляет через тот же ABI события, действия и синхронные callbacks провайдеров. Это не означает, что Lua получает прямой доступ к подсистемам ядра.


2. Фундаментальные технические концепции

Эти сущности пронизывают все домены API. Они обеспечивают стабильность и безопасность.

  • Runtime: Загруженный движок (mc-lua). Регистрируется один раз, создает изолированные Lua-среды для пакетов.
  • Capability (Возможность): Именованная возможность хоста выполнить класс операций. Её доступность определяется сборкой, возможностями хоста, размером ABI, поддержкой рантайма, воркспейсом и активным контекстом. Текущий manifest пакета не является системой выдачи разрешений.
  • Context: Краткоживущий контекст активного вызова MC. Определяет доступные объекты и мутации здесь и сейчас. Сам контекст нельзя использовать вне callback-функции. Handle можно сохранить между callbacks, если это допускает жизненный цикл соответствующего доменного объекта, но вызывать через него host-операции можно только в разрешённом активном контексте.
  • Opaque handle: Защищенная ссылка ({kind, id, generation}) на объект, принадлежащий хосту. Не раскрывает адрес памяти. При закрытии объекта handle становится недействительным, операции возвращают closed, и ссылка никогда не "оживает" повторно.
  • Snapshot & Revision: Неизменяемое описание состояния объекта на конкретной временной отметке (revision). Операции с устаревшими координатами завершаются ошибкой stale_revision, не меняя данные.
  • Error Model: На границе ABI используются стабильные машинные коды (not_supported, closed, stale_revision, provider_busy) и диагностический текст. Lua-ошибки в callback изолируются и не роняют MC.
  • Source (Источник данных): Абстрактное описание откуда взять данные (bytes, локальный файл, процесс, pipeline). Хост сам материализует источник и передает его consumer'у.

3. Иерархия доменов API (Функциональные группы)

API разделены по предметным областям. Workspace определяет область применения пакета и доступный контекст, но не является синонимом API-домена.

3.1. Управление пакетами (Package Model)

Сущности, описывающие жизненный цикл самого расширения.

  1. Package: Единица загрузки. Имеет ID, имя, workspace, точку входа, состояние enabled/disabled и декларацию provides.
  2. Package Descriptor: Декларативное описание (метаданные) пакета. Проверяется до исполнения Lua-кода. Отдельного поля «класс пакета» или списка запрашиваемых host capabilities в текущем manifest нет.
  3. Workspace: Область применения (file manager, editor, viewer, terminal). Определяет контекст.
  4. Package Origin & Precedence: Системный или пользовательский каталог. Пакет с одинаковым ID в более приоритетном origin замещает менее приоритетный.
  5. Indicator: Именованный фрагмент постоянного UI-состояния, принадлежащий пакету.

3.2. Домен Редактора (mc.editor)

Работа с открытым текстовым документом. MC владеет документом, Lua получает его снимок.

  • Editor Document: Хостовый документ. Идентифицируется через handle.
  • Document Info Snapshot: Состояние документа (path, readonly, modified, revision).
  • Position & Range: Координаты в буфере. Завязаны на revision.
  • Selection: Снимок выделения (режим + один или несколько ranges).
  • Edit & Transaction:
    • Edit: Декларативная замена текста в range.
    • Transaction: Атомарный набор edits, создающий одну запись undo.

3.3. Домен Панелей (mc.panel & mc.panel_provider)

Разделение на управление существующими панелями и провайдеры виртуальных пространств.

Базовое управление (существующие панели)

  • Panel & Panel Reference: Временная ссылка на уже существующую активную или пассивную панель MC. Не дает владения виджетом.

Провайдеры (виртуальные пространства)

  • Panel Provider: Глобальная регистрация логического пространства (например, git:, arc:, ftp:). Определяет capabilities, callbacks, действия.
  • Connection: Сохраненное описание точки входа (например, конкретный URL).
  • Provider Instance: Состояние одного открытия провайдера в конкретной панели. Живет пока открыта панель.
  • Panel View: Revisioned snapshot текущего состояния панели (entries, columns, focus). Заменяется целиком после refresh.
  • Panel Entry: Элемент view (snapshot, не файл). Может быть directory-like (навигация) или file-like (контент). Provider использует ID последовательно в пределах instance, а операции над entry дополнительно привязаны к revision текущего view.
  • Column & Presentation: Семантическое поле entry и правила его отображения (хост решает, как рисовать).
  • Panel Selection: Снимок current entry и отмеченных IDs. Передается в action как значение.
  • Content Contract: Механизм связи panel entry с consumer'ом содержимого. Lua callback open_read() возвращает типизированный source (bytes, локальный файл, процесс или pipeline), а runtime bridge при необходимости преобразует его в общий mc_pp_input_stream_t. Благодаря этому штатный consumer, например arcmc, читает данные через stream API, хотя Lua не реализует низкоуровневые callbacks open/read/close самостоятельно.

3.4. Домен Просмотра (mc.ui - Viewer)

Просмотр данных в штатном viewer'е MC.

  • Viewer Source Definition: Глобальное описание семейства источников (имя, callbacks, хелп).
  • Viewer Session: Состояние контроллера от момента create до закрытия.
  • Viewer Controller: Opaque объект, связывающий сессию с host viewer'ом.
  • Viewer Source Specification: Подготовленный immutable snapshot источника для открытия в viewer.

3.5. Общие UI-средства (mc.ui - Dialogs, Alerts)

Общие host-owned элементы интерфейса.

  • Dialog Specification: Декларативное описание модального диалога. Lua не управляет виджетами напрямую.
  • Dialog Control: Типизированный элемент формы (layout-контейнер, label, input, checkbox, radio/select, button, разделитель).
  • Dialog Result: Immutable результат завершенного диалога.
  • Help Reference: Ссылка на package-owned help system.

3.6. Внешние процессы (mc.process)

Контролируемый запуск системных команд.

  • Process Request: Текущий mc.process.run() принимает shell-команду строкой и ограничение max_output. Структурированные argv, рабочая директория и pipeline относятся к typed process source в viewer-source ABI.
  • Process Result: Результат завершения процесса (stdout, stderr, exit status, признаки truncation).
  • Pipeline Source: Композиция process sources.

3.7. События (mc.on)

Механизм подписки на действия MC.

  • Subscription: Регистрация пакета на событие.
  • Event Snapshot: Неизменяемый снимок данных события. Не дает доступа к живому виджету.

4. Поток управления и жизненный цикл (Key Bindings Flow)

Важно показать, как доменная модель работает в динамике.

  1. Нажатие клавиши в MC.
  2. Глобальный keymap преобразует её в MC Command (например, CK_EditNew).
  3. Плагин панели получает команду через handle_key().
  4. Runtime Adapter переводит вызов в Domain Operation (например, вызывает Lua callback new_connection() у провайдера).
  5. Lua-пакет выполняет логику и возвращает результат, предусмотренный конкретной операцией.

Пример:

Shift-F4 → CK_EditNew → runtime adapter → calls provider's Lua function `new_connection()`
F4       → CK_Edit    → runtime adapter → calls `edit_connection(snapshot)`

Clone this wiki locally