| 1 | <!-- English translation of adr/0023-markdown-diagrams-language-tooling.md. Canonical Russian: ../../adr/0023-markdown-diagrams-language-tooling.md --> |
| 2 | |
| 3 | # ADR 0023: Markdown + diagrams (Mermaid/PlantUML) - first-class experience through LSP and workflow |
| 4 | |
| 5 | **Status:** Proposed |
| 6 | **Date:** 2026-04-08 |
| 7 | |
| 8 | ## Related ADRs |
| 9 | |
| 10 | | ADR | Role | |
| 11 | |-----|------| |
| 12 | | [0015](0015-editor-toml-syntax-highlighting.md) | TextMate highlighting as a fast baseline | |
| 13 | | [0008](0008-mcp-contracts-and-testable-infrastructure.md) | external processes and testable abstractions | |
| 14 | | [0021](0021-pfd-mfd-cockpit-attention-model.md) | cockpit attention model | |
| 15 | | [0026](0026-markdown-preview-surfaces-and-placement.md) | **where** the Markdown preview widget is mounted - `workspace.toml`; canon for posting previews | |
| 16 | |
| 17 | ## Summary |
| 18 | |
| 19 | - Markdown + **Mermaid/PlantUML** - first-class via LSP and workflow. |
| 20 | - Kroki, export expanded, authoring - **orthogonal** preview ([0069](0069-markdown-preview-tool-surface-and-renderer-decoupling.md)). |
| 21 | |
| 22 | --- |
| 23 | ## Context |
| 24 | |
| 25 | There are a lot of `*.md` in repo and production scripts, as well as Mermaid/PlantUML diagrams (often right in fenced blocks). The comfort of working with them is usually worse than with C# (diagnostics, completion, navigation, rename links, quick cycle “edit → see the result”). |
| 26 | |
| 27 | Important restrictions: |
| 28 | |
| 29 | - Markdown is a container: “nested languages” live inside fenced blocks, but LSP usually works per file, not per range. |
| 30 | - “Make it like C#” for fenced blocks requires a complex infrastructure: virtual documents, two-way mapping of coordinates/diagnostics, synchronization of edits. |
| 31 | - There are different rendering backends for diagrams (locally, PlantUML Server, Kroki). For some commands (for example, Kroki/PlantUML server), the diagram source goes to an external server - this affects privacy. |
| 32 | |
| 33 | --- |
| 34 | |
| 35 | ## Solution |
| 36 | |
| 37 | Adopt the incremental path “80% value fast”: |
| 38 | |
| 39 | 1. **Markdown becomes first-class via Markdown LSP (`marksman`) as an external process.** |
| 40 | Goal: links/anchors/wikilinks, go-to-definition, references, rename, basic diagnostics - on the entire `*.md` array. |
| 41 | |
| 42 | 2. **PlantUML receives LSP at the individual file level (`*.puml` / `*.plantuml`) via `plantuml-lsp` as an external process.** |
| 43 | Goal: completion/hover/diagnostics in a “real” PlantUML document, without Markdown injection on v1. |
| 44 | |
| 45 | 3. **Mermaid (and PlantUML inside Markdown) on v1 is provided via:** |
| 46 | - baseline: **TextMate highlighting**, snippets/templates (if necessary), |
| 47 | - **preview/render** in Markdown (built-in workflow IDE), |
| 48 | - **workflow commands** for extracting diagrams from Markdown into separate `*.mmd`/`*.puml` files when “language” experience is needed (LSP, navigation, diagnostics). |
| 49 | |
| 50 | 4. **LSP injection into fenced Markdown blocks (virtual documents) - deferred** as a separate ADR/phase after: |
| 51 | - Markdown LSP is stable, |
| 52 | - UX rules are highlighted (how to show diagnostics inside Markdown, how to do quick-fix), |
| 53 | - solved privacy/offline issues for diagram rendering. |
| 54 | |
| 55 | --- |
| 56 | |
| 57 | ## Diagram storage canon + include directive |
| 58 | |
| 59 | **The canonical format for storing diagrams is separate files** next to the documentation: |
| 60 | |
| 61 | - Mermaid: `*.mmd` (or `*.mermaid`) |
| 62 | - PlantUML: `*.puml` / `*.plantuml` |
| 63 | |
| 64 | Markdown (`*.md`) uses fenced blocks **optional**, but prefers **inlining** for: |
| 65 | |
| 66 | - chart revision, |
| 67 | - cleaner diffs, |
| 68 | - enabling LSP at the “real file” level (`plantuml-lsp` for `*.puml`), |
| 69 | - “like C# rename” capabilities (updating links/paths). |
| 70 | |
| 71 | **Syntax include (one line, compatible with the pattern from the `resume` repo):**```mermaid |
| 72 | {{ INCLUDE: example.mmd }} |
| 73 | ``` |
| 74 | |
| 75 | ```plantuml |
| 76 | {{ INCLUDE: example.puml }} |
| 77 | ``` |
| 78 | Optional (not necessary for MVP, but useful for large sections): `INCLUDE_MANIFEST`, `INCLUDE_GLOB` - as in `resume`. |
| 79 | |
| 80 | Rules (v1, benchmark): |
| 81 | |
| 82 | - **case-insensitive** directive (`INCLUDE`/`include`) and allows spaces; |
| 83 | - the default path is considered **relative to the `*.md`** file in which the fenced block is located (as opposed to `resume`, where the path is from the root of the repo); |
| 84 | - limit the include depth (for example, max depth 5) and detect cycles; |
| 85 | - include errors (file not found, loop, too deep) should be displayed in the preview as a clear diagnostic. |
| 86 | |
| 87 | --- |
| 88 | |
| 89 | ## Publishing (so as not to “break external Markdown”) |
| 90 | |
| 91 | Include directives (`{{ INCLUDE: ... }}` and variants) are **not a Markdown standard** and outside of CascadeIDE they can break the rendering of diagrams. |
| 92 | |
| 93 | Principle: |
| 94 | |
| 95 | - **Inside CascadeIDE / in the sources** you can keep an include structure (authoring convenience). |
| 96 | - **Publish/rummage outside** (GitHub/GitLab/Confluence/…): only **assembled/expanded** Markdown variants, where include has already been replaced with the actual text of diagrams/fragments. |
| 97 | |
| 98 | Consequence (product requirement): |
| 99 | |
| 100 | - The IDE should provide an explicit path “**Export / Build expanded Markdown**” (command/operation) so that the user can get a portable version of the document to publish. |
| 101 | |
| 102 | --- |
| 103 | |
| 104 | ## UX details (guideline) |
| 105 | |
| 106 | - **Placement of the Markdown preview widget** (forward / window / MFD, TOML) - **[0026](0026-markdown-preview-surfaces-and-placement.md)**; here - only language, diagrams and workflow commands. |
| 107 | - For diagrams there is an explicit “confidence threshold”: |
| 108 | - if the rendering is done through a server (Kroki/PlantUML server), there is a switch and URL in the settings; |
| 109 | - offline/private mode - through your own instance (or disabling network rendering). |
| 110 | - **Workflow commands (MVP):** |
| 111 | - “Extract diagram to file...” (from fenced `mermaid`/`plantuml` → `*.mmd`/`*.puml` + link/include back), |
| 112 | - “Open diagram in dedicated editor” (as a quick transition to a separate file or to a virtual document in the future), |
| 113 | - “Render diagram” (update preview/image on demand, without constant polling). |
| 114 | |
| 115 | --- |
| 116 | |
| 117 | ## Consequences |
| 118 | |
| 119 | - Markdown will become more comfortable immediately (LSP at the file level). |
| 120 | - PlantUML will get “like a language” experience where it is really needed - in `*.puml`. |
| 121 | - There will be a gap for fenced blocks (there is no full-fledged LSP inside Markdown), but there will be a quick way to “take it out and live normally.” |
| 122 | - An infrastructure of external LSP processes will appear, which can be extended to other languages. |
| 123 | |
| 124 | --- |
| 125 | |
| 126 | ## Rejected alternatives |
| 127 | |
| 128 | - **Immediately do LSP injection into Markdown fenced blocks** - rejected as too much volume/risk for v1 (complicated synchronization and mapping of diagnostics). |
| 129 | - **Rely only on the preview of diagrams without LSP** - rejected: the goal is not only to “see the picture”, but also to “type like a language”. |
| 130 | - **Embedding LSP as an in-process library** - rejected: easier to update/replace external LSP servers, and lower risk of IDE dependency bloat. |
| 131 | |
| 132 | --- |
| 133 | |
| 134 | ## Open questions |
| 135 | |
| 136 | - Where to store and how to configure paths to `marksman` / `plantuml-lsp` (system PATH vs built-in tool manager). |
| 137 | - Support for `.mmd` as a separate document: is a separate “Mermaid mode” (highlighting/snippets/validation) needed without a full LSP. |
| 138 | - What is the format of the link from Markdown to the rendered diagram (regular link to a file, embed image, include-pragma). |