Einstellungen eingefügt, bei funktionen mit bedingungen autovervollständigung eingefügt, readme angepasst

This commit is contained in:
kuro 2026-10-09 23:53:19 +02:00
parent f9f44e0312
commit eeed4e684b
3 changed files with 90 additions and 52 deletions

View File

@ -1,78 +1,84 @@
# BMC TPL Code All-Around
**Linter, Auto-Formatter, IntelliSense und Hover-Dokumentationen für die BMC TPL (Template Language).**[cite: 5]
**Linter, Auto-Formatter, IntelliSense und Hover-Dokumentationen für die BMC TPL (Template Language).**
Diese Visual Studio Code Erweiterung verwandelt deinen Editor in eine vollwertige Entwicklungsumgebung für BMC Discovery TPL-Skripte. Sie nimmt dir Tipparbeit ab, formatiert Code nach strengen Best Practices, verhindert Syntax-Fehler noch vor dem Deployment und versteht projektübergreifende Abhängigkeiten.[cite: 5]
Diese Visual Studio Code Erweiterung verwandelt deinen Editor in eine vollwertige Entwicklungsumgebung für BMC Discovery TPL-Skripte. Sie nimmt dir Tipparbeit ab, formatiert Code nach strengen Best Practices, verhindert Syntax-Fehler noch vor dem Deployment und versteht projektübergreifende Abhängigkeiten.
---
## ✨ Features
### 🤖 Intelligenter Linter (Syntax-Scanner)
Der Linter analysiert den Code in Echtzeit und warnt vor typischen TPL-Fehlern:[cite: 5]
* **Strikte Hierarchie-Prüfung:** Überwacht die korrekte Reihenfolge der Blöcke innerhalb von Patterns und Syncmappings (`metadata` -> `overview` -> `constants` -> `triggers` -> `mapping`/`removal` -> `body`).[cite: 5]
* **Semicolon- & Zuweisungs-Check:** Findet fehlende Semikolons (ignoriert sie aber intelligent in `enumeration`-Blöcken) und warnt, wenn `=` anstelle von `:=` für Zuweisungen genutzt wird.[cite: 5]
* **Block- & Klammer-Tracking:** Erkennt nicht geschlossene Blöcke (wie fehlende `end body;` oder `end pattern;`) und findet ungeschlossene runde `(` oder eckige `[` Klammern.[cite: 5]
* **Pflichtfeld-Validierung:** Prüft, ob auf Modul-Ebene zwingend benötigte Metadaten (`origin`, `author`, `products`, `publishers`, `tree_path`) vorhanden sind und ob im `body` ein initiales `log.debug` Statement steht.[cite: 5]
* **Toleranz-Modus:** Erkennt automatisch TPL-Versionen (z.B. > 1.23) und stuft in neueren Versionen Fehler zu reinen Warnungen herab, um zukünftige Kompatibilität zu gewährleisten.[cite: 5]
Der Linter analysiert den Code in Echtzeit, merkt sich Zustände über Zeilenumbrüche hinweg und warnt vor typischen TPL-Fehlern:
* **Strikte Hierarchie-Prüfung:** Überwacht die korrekte Reihenfolge der Blöcke innerhalb von Patterns und Syncmappings (`metadata` -> `overview` -> `constants` -> `triggers` -> `mapping`/`removal` -> `body`).
* **Smarter Zuweisungs-Check:** Findet fehlende Semikolons (toleriert sie aber in `enumeration`-Blöcken oder bei umgebrochenen Code-Zeilen). Warnt streng mit einem Fehler, wenn `=` anstelle von `:=` für Variablenzuweisungen genutzt wird (außerhalb von legitimen `if`/`where` Vergleichen).
* **Block- & Klammer-Tracking:** Erkennt nicht geschlossene Blöcke (wie fehlende `end body;` oder `end pattern;`) und findet ungeschlossene runde `(` oder eckige `[` Klammern.
* **Pflichtfeld-Validierung:** Prüft, ob auf Modul-Ebene zwingend benötigte Metadaten (`origin`, `author`, `products`, `publishers`, `tree_path`) vorhanden sind und ob im `body` ein initiales `log.debug` Statement steht.
* **Versions-Prüfung:** Gleicht die im Modul deklarierte TPL-Version mit der in deinen Settings definierten Version ab und warnt vor veralteten Skripten.
### ⚙️ Konfigurierbare Plugin-Einstellungen (Settings)
Personalisiere das Plugin direkt über die VS Code Benutzeroberfläche (File > Preferences > Settings > Extensions > BMC TPL Einstellungen):
* **Standard Metadaten:** Hinterlege deine eigenen Werte für `Author`, `Publisher`, `Origin` und den `Tree Path`. Diese werden beim Generieren neuer Module automatisch eingesetzt.
* **TPL Zielversion:** Definiere die TPL-Version (z.B. `23` für 1.23), für die du standardmäßig entwickelst.
* **Live-Reload:** Änderungen an den Einstellungen greifen sofort, ganz ohne Neustart des Editors.
### 🎨 Auto-Formatter & Visual Alignment (`Shift + Alt + F`)
Schluss mit kaputten Einrückungen! Der Formatter bringt deinen Code in Bestform:[cite: 5]
* **VS Code Standard:** Erzwingt strikt 4 Leerzeichen pro Einrückungs-Ebene.[cite: 5]
* **Dynamische Block-Einrückung:** Erkennt automatisch startende und endende Blöcke (`if`, `for`, `pattern`, `table` etc.) und passt die Einrückungsebene an.[cite: 5]
* **Klammer-Gedächtnis (Visual Alignment):** Die Königsdisziplin! Der Formatter merkt sich die spaltengenaue Position von geöffneten Arrays `[` oder Funktionsaufrufen `(` und richtet alle Folgezeilen makellos an dieser Klammer aus. Schließende Klammern werden auf Wunsch perfekt darunter platziert.[cite: 5]
Schluss mit kaputten Einrückungen! Der Formatter bringt deinen Code in Bestform:
* **VS Code Standard:** Erzwingt strikt 4 Leerzeichen pro Einrückungs-Ebene.
* **Dynamische Block-Einrückung:** Erkennt automatisch startende und endende Blöcke (`if`, `for`, `pattern`, `table` etc.) und passt die Einrückungsebene an.
* **Klammer-Gedächtnis (Visual Alignment):** Die Königsdisziplin! Der Formatter merkt sich die spaltengenaue Position von geöffneten Arrays `[` oder Funktionsaufrufen `(` und richtet alle Folgezeilen makellos an dieser Klammer aus.
### 💡 IntelliSense & Autovervollständigung (Cross-File)
Spart extrem viel Zeit beim Coden durch Kontext-Wissen:[cite: 5]
* **Workspace-Scanning:** Importierst du ein Modul (z.B. `from company.helpers import my_helper`), durchsucht das Plugin im Hintergrund dein gesamtes Projekt. Tippst du `my_helper.`, werden dir automatisch alle verfügbaren `define`-Methoden aus der fremden Datei vorgeschlagen![cite: 5]
* **Lokale Namespaces:** Erkennt `definitions`-Blöcke in der gleichen Datei und schlägt deren Methoden vor.[cite: 5]
* **Variablen-Tracking:** Lernt alle Variablen, die du mit `:=` definiert hast, und schlägt sie dir später vor.[cite: 5]
* **Log-Filter:** Nach dem Tippen von `log.` zeigt VS Code strikt nur noch die validen Methoden (`debug`, `info`, `warn`, `error`) an.[cite: 5]
Spart extrem viel Zeit beim Coden durch massives Kontext-Wissen:
* **Volle BMC Standard-Bibliothek:** Nahtlose Integration aller Built-In Funktionen (z.B. `discovery`, `number`, `text`, `model`). Unterstützt Parameter-Überladungen (z.B. `number.toText` wahlweise mit oder ohne Basis) per Tab-Navigation.
* **Workspace-Scanning:** Importierst du ein Modul (z.B. `from company.helpers import my_helper`), durchsucht das Plugin im Hintergrund dein gesamtes Projekt. Tippst du `my_helper.`, werden dir automatisch alle verfügbaren `define`-Methoden vorgeschlagen.
* **Lokale Namespaces:** Erkennt `definitions`-Blöcke in der gleichen Datei und schlägt deren Methoden vor.
* **Variablen-Tracking:** Lernt alle Variablen, die du mit `:=` definiert hast, und schlägt sie dir später vor.
### 🔍 Hover-Dokumentation (Tooltips)
Wenn du mit der Maus über einem Methodennamen, einem Pattern oder einer Tabelle stehen bleibst:[cite: 5]
* **DocString Extraction:** Das Plugin liest Multi-Line-Kommentare (`"""` oder `'''`), die direkt unter einer `define` oder `pattern` Deklaration stehen, aus und rendert sie als saubere Markdown-Tooltips.[cite: 5]
* **Projektübergreifend:** Funktioniert auch für Methoden aus importierten Dateien! Du musst die aktuelle Datei nicht mehr verlassen, um zu sehen, was eine Hilfsfunktion macht.[cite: 5]
Wenn du mit der Maus über einem Methodennamen, einem Pattern oder einer Tabelle stehen bleibst:
* **Offizielle BMC Doku:** Volle Integration der originalen, mehrzeiligen BMC Dokumentationen für alle eingebauten Funktionen (kein Browser mehr nötig!).
* **DocString Extraction:** Liest eigene Multi-Line-Kommentare (`"""` oder `'''`) aus, die unter `define` oder `pattern` Deklarationen stehen, und rendert sie als saubere Markdown-Tooltips (auch projektübergreifend!).
### ⚡ Quick Fixes (Code Actions / Glühbirne)
Bietet sofortige Reparaturoptionen mit einem Klick:[cite: 5]
* **"Fehlende Modul-Metadaten einfügen":** Generiert sofort alle 5 Pflichtfelder im Modul-Metadata-Block.[cite: 5]
* **"Log-Statement einfügen":** Baut das fehlende `log.debug("Start pattern...");` direkt am Anfang des `body`-Blocks ein.[cite: 5]
* **"Tabs zu Spaces":** Ersetzt sofort alle illegalen Tabs (`\t`) in einer Zeile durch jeweils 4 korrekte Leerzeichen.[cite: 5]
Bietet sofortige Reparaturoptionen mit einem Klick:
* **"Fehlende Modul-Metadaten einfügen":** Generiert sofort alle 5 Pflichtfelder im Modul-Metadata-Block.
* **"Log-Statement einfügen":** Baut das fehlende `log.debug("Start pattern...");` direkt am Anfang des `body`-Blocks ein.
* **"Tabs zu Spaces":** Ersetzt sofort alle illegalen Tabs (`\t`) in einer Zeile durch jeweils 4 korrekte Leerzeichen.
---
## 🚀 Snippets (Code-Vorlagen)
Einfach das Keyword tippen und `Enter` drücken, um komplette, perfekt eingerückte Blöcke zu generieren:[cite: 5]
Einfach das Keyword tippen und `Enter` drücken, um komplette, perfekt eingerückte Blöcke zu generieren:
| Keyword | Beschreibung |
| :--- | :--- |
| `tpl_skeleton` | **God-Snippet**: Generiert eine komplett frische `.tpl` Datei inklusive Modul-Definition, Pflicht-Metadaten, Pattern, Triggern und Log-Statements. |[cite: 5]
| `pattern` | Baut einen leeren Pattern-Block inklusive DocString und `end pattern;`. |[cite: 5]
| `syncmapping` | Baut einen leeren Syncmapping-Block inklusive DocString. |[cite: 5]
| `define` | Generiert eine Methodendefinition (`define name(params) ... end define;`). |[cite: 5]
| `metadata`, `overview`, `body`... | Baut den jeweiligen Block auf und platziert den Cursor in der Mitte. |[cite: 5]
| `table` | Erstellt eine Tabelle inklusive des `default -> "unknown";` Fallbacks. |[cite: 5]
| `if`, `for` | Baut Standard-Schleifen und Abfragen. |[cite: 5]
| `tpl_skeleton` | **God-Snippet**: Generiert ein komplett frisches TPL Modul. Nutzt automatisch deine hinterlegten Settings für Metadaten und Version. |
| `pattern` / `syncmapping` | Baut einen leeren Pattern/Syncmapping-Block inklusive DocString und End-Tag. |
| `define` | Generiert eine Methodendefinition (`define name(params) ... end define;`). |
| `metadata`, `overview`, `body`... | Baut den jeweiligen Block auf und platziert den Cursor in der Mitte. |
| `table` | Erstellt eine Tabelle inklusive des `default -> "unknown";` Fallbacks. |
| `if`, `elif`, `else` | Baut bedingte Abfragen inkl. `then` und `end if;` und platziert den Cursor sauber bei der Bedingung. |
| `for`, `while` | Baut Standard-Schleifen inkl. `do` und End-Tag und lässt dich direkt iterieren. |
---
## 🛠️ Installation & Nutzung
1. Das Plugin aktivieren. (Von den Releases das neuste runterladen und einfach die vsix datei in die Add-ons von Visual Studio Code ziehen)[cite: 5]
2. In einem Projekt mit TPL Dateien eine davon öffnen und die Analyse durchlaufen lassen.[cite: 5]
3. Der Linter startet automatisch bei jedem Tastendruck.[cite: 5]
4. **Formatieren:** Rechtsklick -> *Dokument formatieren* (oder `Shift + Alt + F`).[cite: 5]
5. **Autovervollständigung:** Triggert automatisch beim Tippen, speziell nach einem Punkt (`.`) bei Modul-Aufrufen.[cite: 5]
6. **Quick Fixes:** Auf die gelbe/rote Glühbirne am Zeilenanfang klicken oder `Ctrl + .` (Windows/Linux) / `Cmd + .` (Mac) drücken.[cite: 5]
1. Das Plugin aktivieren. (Von den Releases das neueste herunterladen und einfach die `.vsix` Datei in die Add-ons von Visual Studio Code ziehen).
2. In einem Projekt mit TPL Dateien eine davon öffnen und die Analyse durchlaufen lassen.
3. Der Linter startet automatisch bei jedem Tastendruck.
4. **Formatieren:** Rechtsklick -> *Dokument formatieren* (oder `Shift + Alt + F`).
5. **Autovervollständigung:** Triggert automatisch beim Tippen, speziell nach einem Punkt (`.`) bei Modul-Aufrufen.
6. **Quick Fixes:** Auf die gelbe/rote Glühbirne am Zeilenanfang klicken oder `Ctrl + .` (Windows/Linux) / `Cmd + .` (Mac) drücken.
---
## 📜 Lizenz
Dieses Projekt ist unter der **MIT License** lizenziert.[cite: 6]
Dieses Projekt ist unter der **MIT License** lizenziert.
Copyright (c) 2026 Thomas Wehnert[cite: 6]
Copyright (c) 2026 Thomas Wehnert
Jedem, der eine Kopie dieser Software erhält, wird hiermit kostenlos die Erlaubnis erteilt, ohne Einschränkung mit der Software zu handeln, einschließlich und ohne Einschränkung der Rechte zur Nutzung, zum Kopieren, Ändern, Zusammenführen, Veröffentlichen, Verteilen, Unterlizenzieren und/oder Verkaufen von Kopien der Software, sofern der obige Urheberrechtshinweis und dieser Genehmigungshinweis in allen Kopien oder wesentlichen Teilen der Software enthalten sind.[cite: 6] Die Software wird "ohne Mängelgewähr" (as is) zur Verfügung gestellt.[cite: 6]
Jedem, der eine Kopie dieser Software erhält, wird hiermit kostenlos die Erlaubnis erteilt, ohne Einschränkung mit der Software zu handeln, einschließlich und ohne Einschränkung der Rechte zur Nutzung, zum Kopieren, Ändern, Zusammenführen, Veröffentlichen, Verteilen, Unterlizenzieren und/oder Verkaufen von Kopien der Software, sofern der obige Urheberrechtshinweis und dieser Genehmigungshinweis in allen Kopien oder wesentlichen Teilen der Software enthalten sind. Die Software wird "ohne Mängelgewähr" (as is) zur Verfügung gestellt.

View File

@ -112,6 +112,32 @@ export class TplCompletionProvider implements vscode.CompletionItemProvider {
tableItem.insertText = new vscode.SnippetString('table ${1:name}${2:1.0}\n $0\n default -> "unknown";\nend table;');
items.push(tableItem);
// --- Kontrollstrukturen (If, For, While) ---
const ifItem = new vscode.CompletionItem('if', vscode.CompletionItemKind.Snippet);
ifItem.insertText = new vscode.SnippetString('if ${1:condition} then\n $0\nend if;');
ifItem.detail = "If-Bedingung";
items.push(ifItem);
const elifItem = new vscode.CompletionItem('elif', vscode.CompletionItemKind.Snippet);
elifItem.insertText = new vscode.SnippetString('elif ${1:condition} then\n $0');
elifItem.detail = "Else-If-Bedingung";
items.push(elifItem);
const elseItem = new vscode.CompletionItem('else', vscode.CompletionItemKind.Snippet);
elseItem.insertText = new vscode.SnippetString('else\n $0');
items.push(elseItem);
const forItem = new vscode.CompletionItem('for', vscode.CompletionItemKind.Snippet);
forItem.insertText = new vscode.SnippetString('for ${1:item} in${2:list} do\n $0\nend for;');
forItem.detail = "For-Schleife";
items.push(forItem);
const whileItem = new vscode.CompletionItem('while', vscode.CompletionItemKind.Snippet);
whileItem.insertText = new vscode.SnippetString('while ${1:condition} do\n $0\nend while;');
whileItem.detail = "While-Schleife";
items.push(whileItem);
return items;
} else {
const ns = matchDot[1];

View File

@ -3,7 +3,6 @@ import { TplCodeActionProvider } from './TplCodeActionProvider';
import { TplDocumentFormatter } from './TplDocumentFormatter';
import { TplCompletionProvider } from './TplCompletionProvider';
import { TplHoverProvider } from './TplHoverProvider';
import { tplBuiltIns } from './TplBuiltIns';
enum PatternPhase { None = 0, Metadata = 1, Overview = 2, Constants = 3, Triggers = 4, Mapping = 5, Removal = 6, Body = 7 }
@ -14,7 +13,7 @@ export function activate(context: vscode.ExtensionContext) {
vscode.workspace.onDidOpenTextDocument(doc => validateTplDocument(doc, diagnosticCollection));
vscode.workspace.onDidChangeTextDocument(event => validateTplDocument(event.document, diagnosticCollection));
// NEU: Sofort reagieren, wenn in den VS Code Einstellungen etwas geändert wird
// Sofort reagieren, wenn in den VS Code Einstellungen etwas geändert wird
vscode.workspace.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('tpl')) {
for (const doc of vscode.workspace.textDocuments) {
@ -145,13 +144,29 @@ function validateTplDocument(document: vscode.TextDocument, collection: vscode.D
if (inMultiLineComment) { if (line.includes('*/')) {inMultiLineComment = false;} continue; }
if (line.length === 0) { continue; }
// --- HIER IST DER KORRIGIERTE LINTER FÜR ZUWEISUNGEN ---
const lineWithoutStrings = rawLine.replace(/(["'])(?:(?=(\\?))\2.)*?\1/g, '""');
// 1. Schaltet den Condition-Block EIN
if (/\b(if|elif|where)\b/.test(lineWithoutStrings)) {
inConditionBlock = true;
}
// 2. "=" PRÜFUNG (solange der Block noch aktiv ist)
if (lineWithoutStrings.includes('=') && !lineWithoutStrings.includes(':=') && !lineWithoutStrings.includes('>=') && !lineWithoutStrings.includes('<=')) {
if (!inConditionBlock && parenStack.length === 0 && bracketStack.length === 0 && !/\b(matches)\b/.test(lineWithoutStrings)) {
const idx = rawLine.indexOf('=');
if (idx !== -1) {
addDiag(i, idx, idx + 1, "Falsche Zuweisung. In TPL wird ':=' für Zuweisungen genutzt.", vscode.DiagnosticSeverity.Error);
}
}
}
// 3. Schaltet den Condition-Block wieder AUS (greift für die nächste Zeile)
if (/\b(then|do)\b/.test(lineWithoutStrings) || lineWithoutStrings.endsWith(';')) {
inConditionBlock = false;
}
// -------------------------------------------------------
if (isClosingString) {
if (stringNeedsSemicolon && !line.endsWith(';')) {
@ -288,15 +303,6 @@ function validateTplDocument(document: vscode.TextDocument, collection: vscode.D
}
}
if (lineWithoutStrings.includes('=') && !lineWithoutStrings.includes(':=') && !lineWithoutStrings.includes('>=') && !lineWithoutStrings.includes('<=')) {
if (!inConditionBlock && parenStack.length === 0 && bracketStack.length === 0 && !/\b(matches)\b/.test(lineWithoutStrings)) {
const idx = rawLine.indexOf('=');
if (idx !== -1) {
addDiag(i, idx, idx + 1, "Mögliche falsche Zuweisung. In TPL wird ':=' für Zuweisungen genutzt. (Toleriert in Vergleichen/Bedingungen)", vscode.DiagnosticSeverity.Warning);
}
}
}
if (line.startsWith('end pattern') || line.startsWith('end syncmapping')) {
if (activePhaseName !== "") { addDiag(activePhaseLine, 0, activePhaseName.length, `Block '${activePhaseName}' wurde nicht mit 'end ${activePhaseName};' geschlossen.`, vscode.DiagnosticSeverity.Error); }
if (inBlock !== 'pattern') { addDiag(i, 0, 11, "'end pattern' gefunden, ohne offenen Pattern-Block.", vscode.DiagnosticSeverity.Error); }