Перейти к содержанию

ADR 0023: Markdown + диаграммы (Mermaid/PlantUML) — first-class опыт через LSP и workflow

Статус: Proposed
Дата: 2026-04-08

Связанные ADR

ADR Роль
0015 TextMate подсветка как быстрый baseline
0008 внешние процессы и тестируемые абстракции
0021 модель внимания кокпита
0026 где монтируется виджет превью Markdown — workspace.toml; канон по размещению превью

Резюме

  • Markdown + Mermaid/PlantUML — first-class через LSP и workflow.
  • Kroki, export expanded, authoring — ортогонально preview (0069).

Контекст

В repo и в рабочих сценариях много *.md, а также Mermaid/PlantUML диаграмм (часто прямо в fenced-блоках). Комфорт работы с ними обычно хуже, чем с C# (диагностики, completion, навигация, rename ссылок, быстрый цикл “редактирую → вижу результат”).

Важные ограничения:

  • Markdown — контейнер: внутри fenced-блоков живут “вложенные языки”, но LSP обычно работает по файлу, а не по диапазонам.
  • “Сделать как C#” для fenced-блоков требует сложной инфраструктуры: виртуальные документы, двусторонний маппинг координат/диагностик, синхронизация edits.
  • Для диаграмм есть разные бэкенды рендера (локально, PlantUML Server, Kroki). Для части команд (например, Kroki/PlantUML server) исходник диаграммы уходит на внешний сервер — это влияет на приватность.

Решение

Принять инкрементальный путь “80% ценности быстро”:

  1. Markdown становится first-class через Markdown LSP (marksman) как внешний процесс.
    Цель: ссылки/якоря/викилинки, go-to-definition, references, rename, базовые диагностики — на всём массиве *.md.

  2. PlantUML получает LSP на уровне отдельного файла (*.puml / *.plantuml) через plantuml-lsp как внешний процесс.
    Цель: completion/hover/diagnostics в “настоящем” документе PlantUML, без инъекции в Markdown на v1.

  3. Mermaid (и PlantUML внутри Markdown) на v1 обеспечиваются через:

  4. baseline: TextMate подсветка, snippets/шаблоны (при необходимости),
  5. превью/рендер в Markdown (встроенный workflow IDE),
  6. workflow-команды для извлечения диаграмм из Markdown в отдельные *.mmd/*.puml файлы, когда нужен “языковой” опыт (LSP, навигация, диагностики).

  7. Инъекцию LSP в fenced-блоки Markdown (виртуальные документы) — отложить как отдельный ADR/фаза, после того как:

  8. Markdown LSP стабилен,
  9. выделены UX-правила (как показывать диагностики внутри Markdown, как делать quick-fix),
  10. решены вопросы приватности/офлайна для рендера диаграмм.

Канон хранения диаграмм + include-директива

Каноничный формат хранения диаграмм — отдельные файлы рядом с документацией:

  • Mermaid: *.mmd (или *.mermaid)
  • PlantUML: *.puml / *.plantuml

Markdown (*.md) использует fenced-блоки по необходимости, но предпочитает встраивание через include для:

  • реюза диаграмм,
  • более чистых диффов,
  • включения LSP на уровне “настоящего файла” (plantuml-lsp для *.puml),
  • возможности “как C# rename” (обновление ссылок/путей).

Синтаксис include (одна строка, совместим с паттерном из repo resume):

{{ INCLUDE: example.mmd }}
{{ INCLUDE: example.puml }}

Опционально (необязательно для MVP, но полезно для больших разделов): INCLUDE_MANIFEST, INCLUDE_GLOB — как в resume.

Правила (v1, ориентир):

  • директива case-insensitive (INCLUDE/include) и допускает пробелы;
  • путь по умолчанию считается relative к файлу *.md, в котором находится fenced-блок (в отличие от resume, где пути от корня репо);
  • ограничить глубину include (например, max depth 5) и детектить циклы;
  • ошибки include (файл не найден, цикл, слишком глубоко) должны отображаться в превью как понятная диагностика.

Публикация (чтобы не “сломать внешний Markdown”)

Include-директивы ({{ INCLUDE: ... }} и варианты) — не являются стандартом Markdown и вне CascadeIDE могут ломать рендер диаграмм.

Принцип:

  • Внутри CascadeIDE / в исходниках можно держать include-структуру (authoring convenience).
  • Публиковать/шарить наружу (GitHub/GitLab/Confluence/…): только собранные/развёрнутые варианты Markdown, где include уже заменён на реальный текст диаграмм/фрагментов.

Следствие (требование к продукту):

  • IDE должна предоставлять явный путь “Export / Build expanded Markdown” (команда/операция), чтобы пользователь мог получить переносимую версию документа для публикации.

Детали UX (ориентир)

  • Размещение виджета превью Markdown (forward / окно / MFD, TOML) — 0026; здесь — только язык, диаграммы и workflow-команды.
  • Для диаграмм — явный “порог доверия”:
  • если рендер идёт через сервер (Kroki/PlantUML server), в настройках есть выключатель и URL;
  • офлайн/приватный режим — через свой инстанс (или отключение сетевого рендера).
  • Команды workflow (MVP):
  • “Extract diagram to file…” (из fenced mermaid/plantuml*.mmd/*.puml + ссылка/инклюд обратно),
  • “Open diagram in dedicated editor” (как быстрый переход к отдельному файлу или к виртуальному документу в будущем),
  • “Render diagram” (обновить превью/картинку по требованию, без постоянного polling).

Последствия

  • Markdown станет комфортнее сразу (LSP на уровне файлов).
  • PlantUML получит “как язык” опыт там, где это реально нужно — в *.puml.
  • Для fenced-блоков останется разрыв (нет полноценного LSP внутри Markdown), но появится быстрый путь “вынести и жить нормально”.
  • Появится инфраструктура внешних LSP-процессов, которую можно расширять на другие языки.

Отклонённые альтернативы

  • Сразу делать LSP-инъекцию в fenced-блоки Markdown — отклонено как слишком большой объём/риск для v1 (сложная синхронизация и маппинг диагностик).
  • Опереться только на превью диаграмм без LSP — отклонено: цель не только “видеть картинку”, но и “набирать как язык”.
  • Встраивать LSP как библиотеку in-process — отклонено: легче обновлять/заменять внешние LSP-серверы, и ниже риск раздувания зависимостей IDE.

Открытые вопросы

  • Где хранить и как настраивать пути к marksman / plantuml-lsp (system PATH vs встроенный менеджер инструментов).
  • Поддержка .mmd как отдельного документа: нужен ли отдельный “Mermaid mode” (подсветка/snippets/валидация) без полноценного LSP.
  • Какой формат ссылки из Markdown на вынесенную диаграмму (обычная ссылка на файл, embed-картинка, include-pragma).