2026-10-08 20:02:08 +00:00
|
|
|
import * as vscode from 'vscode';
|
2026-10-08 22:36:29 +00:00
|
|
|
import { tplBuiltIns } from './TplBuiltIns';
|
2026-10-08 20:02:08 +00:00
|
|
|
|
|
|
|
|
export class TplHoverProvider implements vscode.HoverProvider {
|
|
|
|
|
async provideHover(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<vscode.Hover | null> {
|
|
|
|
|
const wordRange = document.getWordRangeAtPosition(position, /[a-zA-Z0-9_.]+/);
|
|
|
|
|
if (!wordRange) return null;
|
|
|
|
|
|
|
|
|
|
const fullWord = document.getText(wordRange);
|
|
|
|
|
const currentText = document.getText();
|
|
|
|
|
|
|
|
|
|
let namespace = "";
|
|
|
|
|
let methodOrPatternName = fullWord;
|
|
|
|
|
|
|
|
|
|
if (fullWord.includes('.')) {
|
|
|
|
|
const parts = fullWord.split('.');
|
|
|
|
|
namespace = parts[0];
|
|
|
|
|
methodOrPatternName = parts[1];
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-08 22:36:29 +00:00
|
|
|
// NEU: BMC Built-Ins abfangen und direkt ausgeben!
|
|
|
|
|
if (namespace && tplBuiltIns[namespace] && tplBuiltIns[namespace][methodOrPatternName]) {
|
|
|
|
|
const markdown = new vscode.MarkdownString();
|
|
|
|
|
markdown.appendCodeblock(`${namespace}.${methodOrPatternName}`, 'tpl');
|
|
|
|
|
markdown.appendMarkdown(`---\n*${tplBuiltIns[namespace][methodOrPatternName]}*`);
|
|
|
|
|
return new vscode.Hover(markdown);
|
|
|
|
|
} else if (!namespace && tplBuiltIns['built_in_globals'][methodOrPatternName]) {
|
|
|
|
|
const markdown = new vscode.MarkdownString();
|
|
|
|
|
markdown.appendCodeblock(`${methodOrPatternName}`, 'tpl');
|
|
|
|
|
markdown.appendMarkdown(`---\n*${tplBuiltIns['built_in_globals'][methodOrPatternName]}*`);
|
|
|
|
|
return new vscode.Hover(markdown);
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-08 20:02:08 +00:00
|
|
|
const searchRegex = new RegExp(`^[ \\t]*(?:(?:define[ \\t]+(?:[a-zA-Z0-9_]+[ \\t]+)*${methodOrPatternName}[ \\t]*\\()|(?:(?:pattern|syncmapping|table|enumeration|configuration)[ \\t]+${methodOrPatternName}\\b))`, 'm');
|
|
|
|
|
|
|
|
|
|
if (!namespace) {
|
|
|
|
|
const match = searchRegex.exec(currentText);
|
2026-10-08 22:36:29 +00:00
|
|
|
if (match) return this.buildHover(currentText, match.index);
|
|
|
|
|
return null;
|
2026-10-08 20:02:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const localDefRegex = new RegExp(`^[ \\t]*definitions[ \\t]+${namespace}\\b`, 'm');
|
|
|
|
|
if (localDefRegex.test(currentText)) {
|
|
|
|
|
const match = searchRegex.exec(currentText);
|
2026-10-08 22:36:29 +00:00
|
|
|
if (match) return this.buildHover(currentText, match.index);
|
2026-10-08 20:02:08 +00:00
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const importRegex = new RegExp(`from\\s+([\\w.]+)\\s+import\\s+${namespace}\\b`);
|
|
|
|
|
const importMatch = importRegex.exec(currentText);
|
|
|
|
|
|
|
|
|
|
if (importMatch) {
|
|
|
|
|
const modPath = importMatch[1];
|
|
|
|
|
const uris = await vscode.workspace.findFiles('**/*.tpl', '**/node_modules/**', 50);
|
|
|
|
|
for (const uri of uris) {
|
|
|
|
|
try {
|
|
|
|
|
const docBytes = await vscode.workspace.fs.readFile(uri);
|
|
|
|
|
const docText = Buffer.from(docBytes).toString('utf8');
|
|
|
|
|
const modRegex = new RegExp(`tpl\\s+1\\.\\d+\\s+module\\s+${modPath.replace(/\./g, '\\\\.')}\\s*;`);
|
|
|
|
|
if (modRegex.test(docText)) {
|
|
|
|
|
const match = searchRegex.exec(docText);
|
2026-10-08 22:36:29 +00:00
|
|
|
if (match) return this.buildHover(docText, match.index);
|
2026-10-08 20:02:08 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} catch(e) {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private buildHover(text: string, matchIndex: number): vscode.Hover {
|
|
|
|
|
const docStr = this.extractDocString(text, matchIndex);
|
|
|
|
|
const markdown = new vscode.MarkdownString();
|
|
|
|
|
const declLine = text.substring(matchIndex).split('\n')[0].trim();
|
|
|
|
|
markdown.appendCodeblock(declLine, 'tpl');
|
2026-10-08 22:36:29 +00:00
|
|
|
if (docStr) markdown.appendMarkdown(`---\n*${docStr}*`);
|
|
|
|
|
else markdown.appendMarkdown(`---\n*(Keine Dokumentation gefunden)*`);
|
2026-10-08 20:02:08 +00:00
|
|
|
return new vscode.Hover(markdown);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private extractDocString(text: string, startIndex: number): string | null {
|
|
|
|
|
const lines = text.substring(startIndex).split('\n');
|
|
|
|
|
let docString = "";
|
|
|
|
|
let inDocString = false;
|
|
|
|
|
let quoteType = "";
|
|
|
|
|
for (let j = 1; j < Math.min(15, lines.length); j++) {
|
|
|
|
|
const line = lines[j].trim();
|
|
|
|
|
if (line.length === 0) continue;
|
|
|
|
|
if (!inDocString) {
|
|
|
|
|
if (line.startsWith('"""') || line.startsWith("'''")) {
|
|
|
|
|
inDocString = true;
|
|
|
|
|
quoteType = line.substring(0, 3);
|
2026-10-08 22:36:29 +00:00
|
|
|
if (line.length > 3 && line.endsWith(quoteType)) { docString = line.substring(3, line.length - 3).trim(); break; }
|
2026-10-08 20:02:08 +00:00
|
|
|
const content = line.substring(3).trim();
|
|
|
|
|
if (content) docString += content + "\n";
|
2026-10-08 22:36:29 +00:00
|
|
|
} else { break; }
|
2026-10-08 20:02:08 +00:00
|
|
|
} else {
|
|
|
|
|
if (line.endsWith(quoteType)) {
|
|
|
|
|
const content = line.substring(0, line.length - 3).trim();
|
|
|
|
|
if (content) docString += content;
|
|
|
|
|
break;
|
2026-10-08 22:36:29 +00:00
|
|
|
} else { docString += line + "\n"; }
|
2026-10-08 20:02:08 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return docString.trim() || null;
|
|
|
|
|
}
|
|
|
|
|
}
|