Files
codegraph/Delphi/Docs/07-DFM-FMX-Support.md
T
Olaf Monien 8dfc99572f Delphi-Konzept: DFM/FMX Support hinzugefügt
- Neues Dokument 07-DFM-FMX-Support.md: Format-Referenz, Extraktions-Strategie, DfmExtractor-Konzept
- Neues Fixture MainForm.dfm: Verschachtelte Komponenten, Event-Handler (FormCreate, btnLoginClick, etc.)
- Integration Guide erweitert: DfmExtractor-Implementierung (analog LiquidExtractor), Coding-Style-Hinweise
- NodeKind-Mapping erweitert: DFM-Komponenten als component, Event-Handler als references, Verschachtelung als contains
- Checklist: DFM/FMX von 'Zukunft' auf konkreten Plan (Phase 1b) hochgestuft
- README aktualisiert: DFM/FMX-Support in Ziel, Inhalt und Grammar-Abschnitt aufgenommen
2026-02-11 01:06:16 +01:00

150 lines
5.4 KiB
Markdown

# DFM/FMX Form-Dateien: Format-Referenz & Extraktions-Konzept
Delphi-Projekte bestehen nicht nur aus `.pas`-Dateien, sondern auch aus **Form-Dateien** (`.dfm` für VCL, `.fmx` für FireMonkey). Diese enthalten die visuelle Komponentenhierarchie und — besonders wertvoll für CodeGraph — die **Event-Handler-Verknüpfungen** zwischen UI-Komponenten und Pascal-Methoden.
## Warum DFM/FMX für CodeGraph relevant sind
| Information | Wert für CodeGraph |
|---|---|
| Komponenten-Deklarationen (`object Button1: TButton`) | NodeKind `component` — zeigt welche UI-Elemente existieren |
| Event-Handler (`OnClick = Button1Click`) | EdgeKind `references` — verknüpft UI mit Code in `.pas` |
| Komponenten-Hierarchie (verschachtelte `object`-Blöcke) | EdgeKind `contains` — zeigt Parent-Child-Beziehungen |
| Komponenten-Typ (`TButton`, `TPanel`, `TEdit`) | Metadata — Typ-Information für Impact-Analyse |
**Besonders wertvoll:** Wenn ein Entwickler eine Methode in der `.pas`-Datei umbenennt, zeigt CodeGraph sofort, dass ein DFM-Event-Handler darauf verweist → Impact-Analyse funktioniert über Dateigrenzen hinweg.
## DFM-Textformat
DFM-Dateien können in **Text** oder **Binär** gespeichert werden. Moderne Delphi-Projekte verwenden fast ausschließlich das Textformat (besser für Versionskontrolle). FMX-Dateien verwenden das gleiche Textformat.
### Grundstruktur
```
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Hauptformular'
ClientHeight = 400
ClientWidth = 600
OnCreate = FormCreate
OnDestroy = FormDestroy
object Panel1: TPanel
Left = 0
Top = 0
Width = 600
Height = 50
Align = alTop
object Label1: TLabel
Left = 16
Top = 16
Caption = 'Willkommen'
end
object Button1: TButton
Left = 500
Top = 12
Caption = 'Login'
OnClick = Button1Click
end
end
object Memo1: TMemo
Left = 0
Top = 50
Width = 600
Height = 350
Align = alClient
end
end
```
### Syntax-Regeln
1. **Top-Level:** `object <Name>: <Typ>` — das Formular selbst
2. **Verschachtelte Komponenten:** `object <Name>: <Typ>` innerhalb eines anderen `object`-Blocks
3. **Properties:** `<Key> = <Value>` — einfache Zuweisung
4. **Event-Handler:** `On<Event> = <MethodenName>` — Verknüpfung zu Pascal-Methode
5. **Ende:** `end` schließt jeden `object`-Block
6. **Vererbung:** `inherited <Name>: <Typ>` statt `object` bei geerbten Formularen
7. **Inline-Objekte:** `inline <Name>: <Typ>` für inline erstellte Objekte
### Event-Handler erkennen
Event-Handler sind Properties, deren **Key mit `On` beginnt** und deren **Value ein Bezeichner** (kein String, keine Zahl) ist:
```
OnClick = Button1Click ← Event-Handler → references Button1Click
OnChange = EditChanged ← Event-Handler → references EditChanged
Caption = 'Nicht ein Event' ← Normales Property (String-Wert)
Left = 100 ← Normales Property (Zahl-Wert)
Align = alTop ← Normales Property (Enum-Wert)
```
### Mehrzeilige Properties
Einige Properties erstrecken sich über mehrere Zeilen:
```
SQL.Strings = (
'SELECT * FROM users'
'WHERE active = 1'
'ORDER BY name')
Items.Strings = (
'Option A'
'Option B')
```
Diese sind für CodeGraph weniger relevant, müssen aber beim Parsen korrekt übersprungen werden.
## Extraktions-Strategie: DfmExtractor
Analog zum `LiquidExtractor` und `SvelteExtractor` wird ein **`DfmExtractor`** als Custom Extractor implementiert — **ohne tree-sitter**, rein Regex/Zeilen-basiert.
### Zu extrahierende Nodes
| DFM-Element | CodeGraph NodeKind | Beispiel |
|---|---|---|
| Top-Level `object` | `component` | `Form1: TForm1` |
| Verschachtelte `object` | `component` | `Button1: TButton` |
| `inherited` | `component` | Geerbte Komponente |
### Zu extrahierende Edges
| DFM-Beziehung | CodeGraph EdgeKind | Beschreibung |
|---|---|---|
| Verschachtelung | `contains` | Panel1 enthält Button1 |
| Event-Handler | `references` | Button1 → `Button1Click` (Methode in .pas) |
| Datei enthält Komponente | `contains` | DFM-Datei → Form1 |
### Parsing-Algorithmus (Pseudocode)
```
für jede Zeile:
wenn "object <Name>: <Typ>" oder "inherited <Name>: <Typ>":
→ neuen component-Node erstellen
→ contains-Edge vom Parent
→ auf Stack pushen
wenn "end":
→ Stack poppen
wenn "<Key> = <Value>" und Key beginnt mit "On" und Value ist Bezeichner:
→ references-Edge: aktuelle Komponente → Value (Methodenname)
→ als UnresolvedReference speichern (wird später zur .pas-Methode aufgelöst)
wenn mehrzeiliges Property (endet mit "("):
→ Zeilen überspringen bis ")"
```
### Verknüpfung DFM ↔ PAS
Die Zuordnung DFM → PAS erfolgt über den **Dateinamen**:
- `MainForm.dfm` gehört zu `MainForm.pas` (gleicher Basename)
- Event-Handler `Button1Click` → Methode `TForm1.Button1Click` in der zugehörigen `.pas`-Datei
Diese Verknüpfung erfolgt in der **Resolution-Phase**, nicht beim Parsen.
## Kein tree-sitter nötig
Es gibt keinen tree-sitter Parser für DFM/FMX. Das Format ist aber so einfach strukturiert (zeilenbasiert, keine komplexe Grammatik), dass ein Regex-basierter Parser vollkommen ausreicht — genau wie bei Liquid-Templates.
## Phase
DFM/FMX-Support wird als **Phase 1b** eingeplant — parallel zum Pascal-Support, da die Verknüpfung DFM ↔ PAS den größten Mehrwert liefert, wenn beides gleichzeitig verfügbar ist.