import * as vscode from 'vscode'; import { CompletionStrategy } from './CompletionStrategy'; export class LocalContextCompletion implements CompletionStrategy { public async provideCompletions(document: vscode.TextDocument, position: vscode.Position, linePrefix: string): Promise { const text = document.getText(); const items: vscode.CompletionItem[] = []; // 1. WENN DER USER NACH EINEM PUNKT TIPPT (Cross-File Lookup) const dotMatch = linePrefix.match(/\b([a-zA-Z0-9_]+)\.$/); if (dotMatch) { const prefix = dotMatch[1]; // z.B. "modelling" if (prefix === 'log' || prefix === 'discovery') return undefined; // Built-ins ignorieren // Prüfen, ob der Präfix importiert wurde const importRegex = new RegExp(`from\\s+([a-zA-Z0-9_.]+)\\s+import\\s+${prefix}\\b`); const match = importRegex.exec(text); if (match) { const moduleName = match[1]; // z.B. "Company.software_modelling" const externalItems = await this.resolveImportedMethods(moduleName, prefix); return externalItems; // Nur externe Methoden zurückgeben } return undefined; // Unbekannter Namespace } // 2. LOKALE DEFINITIONS & IMPORTS PARSEN const lines = text.split('\n'); let currentDefBlock = ""; for (let i = 0; i < lines.length; i++) { const line = lines[i]; const defBlockMatch = line.match(/^\s*definitions?\s+([a-zA-Z0-9_]+)/); if (defBlockMatch) { currentDefBlock = defBlockMatch[1]; continue; } if (line.match(/^\s*end\s+definitions?/)) { currentDefBlock = ""; continue; } const defineMatch = line.match(/^\s*define\s+([a-zA-Z0-9_]+)\b/); if (defineMatch) { const funcName = defineMatch[1]; const fullName = currentDefBlock ? `${currentDefBlock}.${funcName}` : funcName; const item = new vscode.CompletionItem(fullName, vscode.CompletionItemKind.Function); item.detail = currentDefBlock ? `Local Function in '${currentDefBlock}'` : `Local Function`; item.insertText = new vscode.SnippetString(`${fullName}(\${1:params});$0`); items.push(item); } } // Imports für die globale Worterkennung bereitstellen const fromImportRegex = /from\s+([a-zA-Z0-9_.]+)\s+import\s+([a-zA-Z0-9_]+)/g; let matchVar; while ((matchVar = fromImportRegex.exec(text)) !== null) { const item = new vscode.CompletionItem(matchVar[2], vscode.CompletionItemKind.Module); item.detail = `Imported Definitions from ${matchVar[1]}`; items.push(item); } const varRegex = /([a-zA-Z0-9_]+)\s*:=/g; const foundVars = new Set(); while ((matchVar = varRegex.exec(text)) !== null) { if (matchVar[1] !== 'host') { foundVars.add(matchVar[1]); } } for (const v of foundVars) { items.push(new vscode.CompletionItem(v, vscode.CompletionItemKind.Variable)); } return items; } // Hilfsmethode: Sucht im Workspace nach der anderen Datei! private async resolveImportedMethods(moduleName: string, defBlockName: string): Promise { const items: vscode.CompletionItem[] = []; // Sucht alle .tpl Dateien im Projekt const files = await vscode.workspace.findFiles('**/*.tpl', '**/node_modules/**'); for (const file of files) { const doc = await vscode.workspace.openTextDocument(file); const text = doc.getText(); // Ist das das gesuchte Modul? (Punkte escapen) const moduleRegex = new RegExp(`tpl\\s+1\\.\\d+\\s+module\\s+${moduleName.replace(/\./g, '\\.')}\\s*;`); if (moduleRegex.test(text)) { // Modul gefunden! Jetzt die Defines im entsprechenden Block auslesen const lines = text.split('\n'); let inTargetBlock = false; for (const line of lines) { if (line.match(new RegExp(`^\\s*definitions?\\s+${defBlockName}\\b`))) { inTargetBlock = true; continue; } if (inTargetBlock && line.match(/^\s*end\s+definitions?/)) { inTargetBlock = false; break; } if (inTargetBlock) { const defineMatch = line.match(/^\s*define\s+([a-zA-Z0-9_]+)\b/); if (defineMatch) { const funcName = defineMatch[1]; const item = new vscode.CompletionItem(funcName, vscode.CompletionItemKind.Function); item.detail = `Method from ${moduleName}`; item.insertText = new vscode.SnippetString(`${funcName}(\${1:params});$0`); items.push(item); } } } break; // Datei gefunden und geparst, wir können abbrechen } } return items; } }