const vscode = require('vscode'); // Type information for Baba Yaga const builtinFunctions = new Map([ ['io.out', { name: 'io.out', kind: 'function', signature: 'io.out(value: any) -> void', description: 'Print value to console' }], ['io.in', { name: 'io.in', kind: 'function', signature: 'io.in() -> String', description: 'Read input from console' }], ['map', { name: 'map', kind: 'function', signature: 'map(func: (T) -> U, list: [T]) -> [U]', description: 'Apply function to each element' }], ['filter', { name: 'filter', kind: 'function', signature: 'filter(pred: (T) -> Bool, list: [T]) -> [T]', description: 'Filter list by predicate' }], ['reduce', { name: 'reduce', kind: 'function', signature: 'reduce(func: (acc: T, item: T) -> T, init: T, list: [T]) -> T', description: 'Fold list to single value' }], ['append', { name: 'append', kind: 'function', signature: 'append(list: [T], item: T) -> [T]', description: 'Add item to end of list' }], ['set', { name: 'set', kind: 'function', signature: 'set(table: Table, key: String, value: any) -> Table', description: 'Set table property' }], ['merge', { name: 'merge', kind: 'function', signature: 'merge(table1: Table, table2: Table) -> Table', description: 'Merge two tables' }], ['shape', { name: 'shape', kind: 'function', signature: 'shape(value: any) -> Table', description: 'Get value metadata' }] ]); // String functions const stringFunctions = ['concat', 'split', 'join', 'length', 'substring', 'replace', 'trim', 'upper', 'lower']; stringFunctions.forEach(func => { builtinFunctions.set(`str.${func}`, { name: `str.${func}`, kind: 'function', signature: `str.${func}(...args) -> String`, description: `String ${func} operation` }); }); // Math functions const mathFunctions = ['abs', 'sign', 'floor', 'ceil', 'round', 'trunc', 'min', 'max', 'clamp', 'pow', 'sqrt', 'exp', 'log', 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'atan2', 'deg', 'rad', 'random', 'randomInt']; mathFunctions.forEach(func => { builtinFunctions.set(`math.${func}`, { name: `math.${func}`, kind: 'function', signature: `math.${func}(...args) -> Number`, description: `Math ${func} operation` }); }); // Keywords const keywords = new Map([ ['when', { name: 'when', kind: 'keyword', description: 'Pattern matching expression' }], ['then', { name: 'then', kind: 'keyword', description: 'Pattern match result' }], ['is', { name: 'is', kind: 'keyword', description: 'Pattern match operator' }], ['Ok', { name: 'Ok', kind: 'keyword', description: 'Success result constructor' }], ['Err', { name: 'Err', kind: 'keyword', description: 'Error result constructor' }], ['true', { name: 'true', kind: 'keyword', description: 'Boolean true value' }], ['false', { name: 'false', kind: 'keyword', description: 'Boolean false value' }], ['PI', { name: 'PI', kind: 'keyword', description: 'Mathematical constant π' }], ['INFINITY', { name: 'INFINITY', kind: 'keyword', description: 'Positive infinity' }], ['and', { name: 'and', kind: 'keyword', description: 'Logical AND operator' }], ['or', { name: 'or', kind: 'keyword', description: 'Logical OR operator' }], ['xor', { name: 'xor', kind: 'keyword', description: 'Logical XOR operator' }] ]); // Types const types = new Map([ ['Bool', { name: 'Bool', kind: 'type', description: 'Boolean type (true/false)' }], ['Int', { name: 'Int', kind: 'type', description: 'Integer type' }], ['Float', { name: 'Float', kind: 'type', description: 'Floating-point type' }], ['String', { name: 'String', kind: 'type', description: 'String type' }], ['List', { name: 'List', kind: 'type', description: 'List type [T]' }], ['Table', { name: 'Table', kind: 'type', description: 'Table type {key: value}' }], ['Result', { name: 'Result', kind: 'type', description: 'Result type (Ok T | Err String)' }], ['Number', { name: 'Number', kind: 'type', description: 'Numeric supertype (Int | Float)' }] ]); // Helper functions function findFunctionDefinition(document, functionName) { const text = document.getText(); const lines = text.split('\n'); for (let i = 0; i < lines.length; i++) { const line = lines[i]; const match = line.match(new RegExp(`\\b${functionName}\\s*:\\s*(.+?)\\s*->\\s*(.+?)\\s*;`)); if (match) { const signature = `${functionName} : ${match[1]} -> ${match[2]}`; const startPos = document.positionAt(text.indexOf(line)); const endPos = document.positionAt(text.indexOf(line) + line.length); return { signature, range: new vscode.Range(startPos, endPos), description: `Function defined at line ${i + 1}` }; } } return null; } // Helper function to check if position is in a Baba Yaga code block function isInBabaYagaCodeBlock(document, position) { const text = document.getText(); const line = document.lineAt(position.line).text; // Check if we're in a markdown file if (document.languageId === 'markdown') { // Look for ```baba code blocks const lines = text.split('\n'); let inBabaBlock = false; for (let i = 0; i <= position.line; i++) { const currentLine = lines[i]; if (currentLine.trim().startsWith('```baba') || currentLine.trim().startsWith('```baba-yaga') || currentLine.trim().startsWith('```by')) { inBabaBlock = true; } else if (currentLine.trim() === '```' && inBabaBlock) { inBabaBlock = false; } } return inBabaBlock; } return document.languageId === 'baba-yaga'; } // Hover Provider class BabaYagaHoverProvider { provideHover(document, position, token) { // Only provide hover for Baba Yaga content if (!isInBabaYagaCodeBlock(document, position)) { return null; } const wordRange = document.getWordRangeAtPosition(position); if (!wordRange) return null; const word = document.getText(wordRange); // Check built-in functions const builtin = builtinFunctions.get(word); if (builtin) { return new vscode.Hover([ `**${builtin.name}**`, `\`${builtin.signature}\``, builtin.description || '' ]); } // Check keywords const keyword = keywords.get(word); if (keyword) { return new vscode.Hover([ `**${keyword.name}** (keyword)`, keyword.description || '' ]); } // Check types const type = types.get(word); if (type) { return new vscode.Hover([ `**${type.name}** (type)`, type.description || '' ]); } // Check for function definitions in the document const functionDef = findFunctionDefinition(document, word); if (functionDef) { return new vscode.Hover([ `**${word}** (function)`, `\`${functionDef.signature}\``, functionDef.description || '' ]); } return null; } } // Completion Provider class BabaYagaCompletionProvider { provideCompletionItems(document, position, token, context) { // Only provide completion for Baba Yaga content if (!isInBabaYagaCodeBlock(document, position)) { return []; } const items = []; // Add built-in functions builtinFunctions.forEach((func, name) => { const item = new vscode.CompletionItem(name, vscode.CompletionItemKind.Function); item.detail = func.signature; item.documentation = func.description; items.push(item); }); // Add keywords keywords.forEach((keyword, name) => { const item = new vscode.CompletionItem(name, vscode.CompletionItemKind.Keyword); item.documentation = keyword.description; items.push(item); }); // Add types types.forEach((type, name) => { const item = new vscode.CompletionItem(name, vscode.CompletionItemKind.TypeParameter); item.documentation = type.description; items.push(item); }); // Add operators const operators = ['+', '-', '*', '/', '%', '=', '!=', '>', '<', '>=', '<=', '->', '..', ':', 'and', 'or', 'xor']; operators.forEach(op => { const item = new vscode.CompletionItem(op, vscode.CompletionItemKind.Operator); items.push(item); }); return items; } } // Definition Provider class BabaYagaDefinitionProvider { provideDefinition(document, position, token) { // Only provide definition for Baba Yaga content if (!isInBabaYagaCodeBlock(document, position)) { return null; } const wordRange = document.getWordRangeAtPosition(position); if (!wordRange) return null; const word = document.getText(wordRange); // Find function definition in the document const functionDef = findFunctionDefinition(document, word); if (functionDef) { return new vscode.Location(document.uri, functionDef.range); } return null; } } // Reference Provider class BabaYagaReferenceProvider { provideReferences(document, position, context, token) { // Only provide references for Baba Yaga content if (!isInBabaYagaCodeBlock(document, position)) { return []; } const wordRange = document.getWordRangeAtPosition(position); if (!wordRange) return null; const word = document.getText(wordRange); const references = []; // Find all references in the document const text = document.getText(); const regex = new RegExp(`\\b${word}\\b`, 'g'); let match; while ((match = regex.exec(text)) !== null) { const startPos = document.positionAt(match.index); const endPos = document.positionAt(match.index + match[0].length); references.push(new vscode.Location(document.uri, new vscode.Range(startPos, endPos))); } return references; } } // Diagnostic Provider class BabaYagaDiagnosticProvider { constructor() { this.diagnosticCollection = vscode.languages.createDiagnosticCollection('baba-yaga'); vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument.bind(this)); } onDidChangeTextDocument(event) { if (event.document.languageId === 'baba-yaga' || event.document.languageId === 'markdown' || event.document.languageId === 'baba' || event.document.languageId === 'by') { this.updateDiagnostics(event.document); } } updateDiagnostics(document) { // Disable automatic diagnostics to prevent false semicolon warnings // Baba Yaga has different syntax rules than JavaScript/TypeScript this.diagnosticCollection.set(document.uri, []); } needsSemicolon(line) { const trimmed = line.trim(); // Skip empty lines if (!trimmed) return false; // Skip comment-only lines if (trimmed.startsWith('//')) return false; // Extract code part before any inline comment const commentIndex = trimmed.indexOf('//'); const codePart = commentIndex >= 0 ? trimmed.substring(0, commentIndex).trim() : trimmed; // Skip if no actual code content if (!codePart) return false; // Skip single identifiers or incomplete expressions (likely continuations) if (codePart.match(/^\s*[a-zA-Z_][a-zA-Z0-9_]*\s*$/)) { return false; } // Lines that don't need semicolons if (codePart.endsWith(';') || codePart.endsWith('{') || codePart.endsWith('}') || codePart.endsWith('then') || // Pattern match continuations codePart.endsWith('is')) { // Pattern match starts return false; } // Lines that are likely continuations (start with pattern keywords) if (codePart.match(/^\s*(when|then|is|\d+|"[^"]*"|true|false|Ok|Err|_)\s/)) { return false; } // Skip arrow function definitions (they don't need semicolons) if (codePart.includes('->')) return false; // Skip pattern matching expressions if (codePart.includes('when') || codePart.includes('is') || codePart.includes('then')) return false; // Skip table/record definitions if (codePart.match(/\{[^}]*\}/)) return false; // Skip list definitions if (codePart.match(/\[[^\]]*\]/)) return false; // Skip function calls that might be part of larger expressions if (codePart.match(/[a-zA-Z_][a-zA-Z0-9_]*\s*\(/)) return false; // This line needs a semicolon return true; } } // Type Hints Provider - Shows type information in different modes class BabaYagaTypeHintsProvider { constructor(mode = 'above') { this.mode = mode; // Inline decorations (after expressions) this.inlineDecorations = vscode.window.createTextEditorDecorationType({ after: { margin: '0 0 0 1em', color: new vscode.ThemeColor('editorCodeLens.foreground'), fontStyle: 'italic', fontSize: '0.9em' } }); // Above-line decorations (on line above expressions) - DISABLED // this.aboveDecorations = vscode.window.createTextEditorDecorationType({ // after: { // contentText: '', // color: new vscode.ThemeColor('editorCodeLens.foreground'), // fontStyle: 'italic', // fontSize: '1em', // textDecoration: 'none; display: block; text-align: right; margin-right: 1em; line-height: 1.5;' // } // }); } updateTypeHints(editor) { if (!editor || !isInBabaYagaCodeBlock(editor.document, editor.selection.active)) { return; } // Clear previous decorations editor.setDecorations(this.inlineDecorations, []); // editor.setDecorations(this.aboveDecorations, []); if (this.mode === 'none') { return; // No active type hints, only hover } const document = editor.document; const text = document.getText(); const inlineDecorations = []; // const aboveDecorations = []; // Not used when above mode is disabled // Parse function definitions to build type map const functionTypes = new Map(); const lines = text.split('\n'); for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); const funcMatch = line.match(/^(\w+)\s*:\s*(.+?)\s*->\s*(.+?)\s*;$/); if (funcMatch) { const [, funcName, params, returnType] = funcMatch; functionTypes.set(funcName, { params, returnType }); } } // Find expressions to add type hints for (let i = 0; i < lines.length; i++) { const line = lines[i]; // Skip comments if (line.trim().startsWith('//')) { continue; } // Function calls const funcCallMatch = line.match(/\b(\w+)\s*\(/g); if (funcCallMatch) { funcCallMatch.forEach(match => { const funcName = match.replace(/\s*\($/, ''); const typeInfo = this.getTypeInfo(funcName, functionTypes); if (typeInfo) { const matchIndex = line.indexOf(match); const lineStartIndex = text.split('\n').slice(0, i).join('\n').length + (i > 0 ? 1 : 0); const startPos = document.positionAt(lineStartIndex + matchIndex); const endPos = document.positionAt(lineStartIndex + matchIndex + match.length); if (this.mode === 'inline') { inlineDecorations.push({ range: new vscode.Range(startPos, endPos), renderOptions: { after: { contentText: ` : ${typeInfo}`, color: new vscode.ThemeColor('editorCodeLens.foreground'), fontStyle: 'italic', fontSize: '0.9em' } } }); } // Above mode disabled - commented out // } else if (this.mode === 'above') { // const lineAbove = new vscode.Position(Math.max(0, startPos.line - 1), 0); // aboveDecorations.push({ // range: new vscode.Range(lineAbove, lineAbove), // renderOptions: { // after: { // contentText: `\n${' '.repeat(Math.max(0, startPos.character - typeInfo.length - 3))} : ${typeInfo}`, // color: new vscode.ThemeColor('editorCodeLens.foreground'), // fontStyle: 'italic', // fontSize: '0.8em' // } // } // }); // } } }); } // Member access (str.func, math.func) const memberMatch = line.match(/\b(\w+)\.(\w+)\s*\(/g); if (memberMatch) { memberMatch.forEach(match => { const [, namespace, funcName] = match.match(/\b(\w+)\.(\w+)\s*\(/); const typeInfo = this.getBuiltinTypeInfo(namespace, funcName); if (typeInfo) { const matchIndex = line.indexOf(match); const lineStartIndex = text.split('\n').slice(0, i).join('\n').length + (i > 0 ? 1 : 0); const startPos = document.positionAt(lineStartIndex + matchIndex); const endPos = document.positionAt(lineStartIndex + matchIndex + match.length); if (this.mode === 'inline') { inlineDecorations.push({ range: new vscode.Range(startPos, endPos), renderOptions: { after: { contentText: ` : ${typeInfo}`, color: new vscode.ThemeColor('editorCodeLens.foreground'), fontStyle: 'italic', fontSize: '0.9em' } } }); } // Above mode disabled - commented out // else if (this.mode === 'above') { // const lineAbove = new vscode.Position(Math.max(0, startPos.line - 1), 0); // aboveDecorations.push({ // range: new vscode.Range(lineAbove, lineAbove), // renderOptions: { // after: { // contentText: `\n${' '.repeat(Math.max(0, startPos.character - typeInfo.length - 3))} : ${typeInfo}`, // color: new vscode.ThemeColor('editorCodeLens.foreground'), // fontStyle: 'italic', // fontSize: '0.8em' // } // } // }); // } } }); } // When expressions if (line.includes('when') && line.includes('is')) { const matchIndex = line.indexOf('when'); const lineStartIndex = text.split('\n').slice(0, i).join('\n').length + (i > 0 ? 1 : 0); const startPos = document.positionAt(lineStartIndex + matchIndex); const endPos = document.positionAt(lineStartIndex + line.length); if (this.mode === 'inline') { inlineDecorations.push({ range: new vscode.Range(startPos, endPos), renderOptions: { after: { contentText: ' : Pattern Matching', color: new vscode.ThemeColor('editorCodeLens.foreground'), fontStyle: 'italic', fontSize: '0.9em' } } }); } // Above mode disabled - commented out // else if (this.mode === 'above') { // const lineAbove = new vscode.Position(Math.max(0, startPos.line - 1), 0); // aboveDecorations.push({ // range: new vscode.Range(lineAbove, lineAbove), // renderOptions: { // after: { // contentText: `\n${' '.repeat(Math.max(0, startPos.character - 18))} : Pattern Matching`, // color: new vscode.ThemeColor('editorCodeLens.foreground'), // fontStyle: 'italic', // fontSize: '0.8em' // } // } // }); // } } // Result constructors if (line.includes('Ok') || line.includes('Err')) { const okIndex = line.indexOf('Ok'); const errIndex = line.indexOf('Err'); const matchIndex = okIndex !== -1 ? okIndex : errIndex; if (matchIndex !== -1) { const lineStartIndex = text.split('\n').slice(0, i).join('\n').length + (i > 0 ? 1 : 0); const startPos = document.positionAt(lineStartIndex + matchIndex); const endPos = document.positionAt(lineStartIndex + line.length); if (this.mode === 'inline') { inlineDecorations.push({ range: new vscode.Range(startPos, endPos), renderOptions: { after: { contentText: ' : Result', color: new vscode.ThemeColor('editorCodeLens.foreground'), fontStyle: 'italic', fontSize: '0.9em' } } }); } // Above mode disabled - commented out // else if (this.mode === 'above') { // const lineAbove = new vscode.Position(Math.max(0, startPos.line - 1), 0); // aboveDecorations.push({ // range: new vscode.Range(lineAbove, lineAbove), // renderOptions: { // after: { // contentText: `\n${' '.repeat(Math.max(0, startPos.character - 12))} : Result`, // fontSize: '0.8em' // } // } // }); // } } } } // Apply decorations based on mode if (this.mode === 'inline') { editor.setDecorations(this.inlineDecorations, inlineDecorations); } // if (this.mode === 'above') { // editor.setDecorations(this.aboveDecorations, aboveDecorations); // } } getTypeInfo(funcName, functionTypes) { // Check built-in functions first const builtin = builtinFunctions.get(funcName); if (builtin) { return builtin.signature.split(' -> ')[1] || 'any'; } // Check user-defined functions const userFunc = functionTypes.get(funcName); if (userFunc) { return userFunc.returnType; } return null; } getBuiltinTypeInfo(namespace, funcName) { const fullName = `${namespace}.${funcName}`; const builtin = builtinFunctions.get(fullName); if (builtin) { return builtin.signature.split(' -> ')[1] || 'any'; } return null; } dispose() { this.inlineDecorations.dispose(); // this.aboveDecorations.dispose(); } } // Command implementations async function showTypeInfo() { const editor = vscode.window.activeTextEditor; if (!editor) return; const position = editor.selection.active; // Only work in Baba Yaga content if (!isInBabaYagaCodeBlock(editor.document, position)) { vscode.window.showInformationMessage('This command only works in Baba Yaga code blocks'); return; } const wordRange = editor.document.getWordRangeAtPosition(position); if (!wordRange) return; const word = editor.document.getText(wordRange); const type = builtinFunctions.get(word) || keywords.get(word) || types.get(word); if (type) { vscode.window.showInformationMessage(`${word}: ${type.description || type.signature || type.name}`); } } async function goToDefinition() { const editor = vscode.window.activeTextEditor; if (!editor) return; const position = editor.selection.active; // Only work in Baba Yaga content if (!isInBabaYagaCodeBlock(editor.document, position)) { vscode.window.showInformationMessage('This command only works in Baba Yaga code blocks'); return; } const wordRange = editor.document.getWordRangeAtPosition(position); if (!wordRange) return; const word = editor.document.getText(wordRange); const functionDef = findFunctionDefinition(editor.document, word); if (functionDef) { editor.selection = new vscode.Selection(functionDef.range.start, functionDef.range.end); editor.revealRange(functionDef.range); } } async function findReferences() { const editor = vscode.window.activeTextEditor; if (!editor) return; const position = editor.selection.active; // Only work in Baba Yaga content if (!isInBabaYagaCodeBlock(editor.document, position)) { vscode.window.showInformationMessage('This command only works in Baba Yaga code blocks'); return; } const wordRange = editor.document.getWordRangeAtPosition(position); if (!wordRange) return; const word = editor.document.getText(wordRange); await vscode.commands.executeCommand('editor.action.referenceSearch.trigger'); } async function showFunctionSignature() { const editor = vscode.window.activeTextEditor; if (!editor) return; const position = editor.selection.active; // Only work in Baba Yaga content if (!isInBabaYagaCodeBlock(editor.document, position)) { vscode.window.showInformationMessage('This command only works in Baba Yaga code blocks'); return; } const wordRange = editor.document.getWordRangeAtPosition(position); if (!wordRange) return; const word = editor.document.getText(wordRange); const builtin = builtinFunctions.get(word); if (builtin) { vscode.window.showInformationMessage(`${word}: ${builtin.signature}`); } } // Baba Yaga Syntax Auto-Fix Rules const syntaxFixRules = [ // Rule 1: Function calls in comparisons { name: "Function Calls in Comparisons", pattern: /(\w+(?:\.\w+)?(?:\s+[^><=!]+)*)\s*([><=!]=?)\s*([^;,\s]+)/g, replacement: "($1) $2 $3", description: "Wrap function calls in parentheses when used in comparisons" }, // Rule 2: Logical operators { name: "Logical Operators", pattern: /([^;\s]+)\s+(and|or)\s+([^;\s]+)/g, replacement: "($1) $2 ($3)", description: "Wrap logical expressions in parentheses" }, // Rule 3: Complex arithmetic in comparisons { name: "Complex Arithmetic in Comparisons", pattern: /([^;\s]*[\+\-\*\/][^;\s]*)\s*([><=!]=?)\s*([^;,\s]+)/g, replacement: "($1) $2 $3", description: "Wrap arithmetic expressions in parentheses when used in comparisons" }, // Rule 4: Nested function calls in comparisons { name: "Nested Function Calls in Comparisons", pattern: /(\w+(?:\.\w+)?\s*\([^)]+\))\s*([><=!]=?)\s*([^;,\s]+)/g, replacement: "($1) $2 $3", description: "Wrap nested function calls in parentheses when used in comparisons" } ]; // Function to apply syntax fixes function applySyntaxFixes(editor) { const document = editor.document; const text = document.getText(); let modifiedText = text; let hasChanges = false; // Apply each rule in order for (const rule of syntaxFixRules) { const matches = [...modifiedText.matchAll(rule.pattern)]; if (matches.length > 0) { modifiedText = modifiedText.replace(rule.pattern, rule.replacement); hasChanges = true; } } if (hasChanges) { // Create edit const fullRange = new vscode.Range( document.positionAt(0), document.positionAt(text.length) ); const edit = new vscode.WorkspaceEdit(); edit.replace(document.uri, fullRange, modifiedText); // Apply the edit return vscode.workspace.applyEdit(edit); } return Promise.resolve(false); } // Function to show syntax fix suggestions function showSyntaxFixSuggestions(editor) { const document = editor.document; const text = document.getText(); const suggestions = []; for (const rule of syntaxFixRules) { const matches = [...text.matchAll(rule.pattern)]; if (matches.length > 0) { suggestions.push({ rule: rule.name, count: matches.length, description: rule.description, examples: matches.slice(0, 3).map(match => match[0]) }); } } if (suggestions.length > 0) { const message = suggestions.map(s => `${s.rule}: ${s.count} issue(s) found\n ${s.description}\n Examples: ${s.examples.join(', ')}` ).join('\n\n'); vscode.window.showInformationMessage( `Found ${suggestions.length} syntax issues that can be auto-fixed:\n\n${message}`, { modal: true } ); } else { vscode.window.showInformationMessage('No syntax issues found that can be auto-fixed.'); } } // Extension activation function activate(context) { console.log('Baba Yaga extension is now active!'); // Register commands context.subscriptions.push( vscode.commands.registerCommand('baba-yaga.showTypeInfo', showTypeInfo), vscode.commands.registerCommand('baba-yaga.goToDefinition', goToDefinition), vscode.commands.registerCommand('baba-yaga.findReferences', findReferences), vscode.commands.registerCommand('baba-yaga.showFunctionSignature', showFunctionSignature), vscode.commands.registerCommand('baba-yaga.autoFixSyntax', () => { const editor = vscode.window.activeTextEditor; if (editor && (editor.document.languageId === 'baba-yaga' || isInBabaYagaCodeBlock(editor.document, editor.selection.active))) { applySyntaxFixes(editor).then(wasFixed => { if (wasFixed) { vscode.window.showInformationMessage('Syntax fixes applied successfully!'); } else { vscode.window.showInformationMessage('No syntax issues found to fix.'); } }); } else { vscode.window.showInformationMessage('This command only works in Baba Yaga code.'); } }), vscode.commands.registerCommand('baba-yaga.showSyntaxIssues', () => { const editor = vscode.window.activeTextEditor; if (editor && (editor.document.languageId === 'baba-yaga' || isInBabaYagaCodeBlock(editor.document, editor.selection.active))) { showSyntaxFixSuggestions(editor); } else { vscode.window.showInformationMessage('This command only works in Baba Yaga code.'); } }) ); // Register language features const config = vscode.workspace.getConfiguration('baba-yaga'); if (config.get('enableTypeHints')) { context.subscriptions.push( vscode.languages.registerHoverProvider('baba-yaga', new BabaYagaHoverProvider()), vscode.languages.registerHoverProvider('markdown', new BabaYagaHoverProvider()), vscode.languages.registerCompletionItemProvider('baba-yaga', new BabaYagaCompletionProvider(), '.', ':', '>'), vscode.languages.registerCompletionItemProvider('markdown', new BabaYagaCompletionProvider(), '.', ':', '>') ); } if (config.get('enableFunctionReferences')) { context.subscriptions.push( vscode.languages.registerDefinitionProvider('baba-yaga', new BabaYagaDefinitionProvider()), vscode.languages.registerDefinitionProvider('markdown', new BabaYagaDefinitionProvider()), vscode.languages.registerReferenceProvider('baba-yaga', new BabaYagaReferenceProvider()), vscode.languages.registerReferenceProvider('markdown', new BabaYagaReferenceProvider()) ); } if (config.get('enableErrorChecking')) { context.subscriptions.push( new BabaYagaDiagnosticProvider() ); } // Register type hints provider based on mode const typeHintMode = config.get('typeHintMode'); if (typeHintMode !== 'none') { const typeHintsProvider = new BabaYagaTypeHintsProvider(typeHintMode); context.subscriptions.push(typeHintsProvider); // Update type hints when text changes vscode.workspace.onDidChangeTextDocument(event => { if (event.document.languageId === 'baba-yaga' || event.document.languageId === 'markdown') { const editor = vscode.window.activeTextEditor; if (editor && editor.document === event.document) { typeHintsProvider.updateTypeHints(editor); } } }); // Update type hints when switching editors vscode.window.onDidChangeActiveTextEditor(editor => { if (editor && (editor.document.languageId === 'baba-yaga' || editor.document.languageId === 'markdown')) { typeHintsProvider.updateTypeHints(editor); } }); // Initial update for current editor const currentEditor = vscode.window.activeTextEditor; if (currentEditor && (currentEditor.document.languageId === 'baba-yaga' || currentEditor.document.languageId === 'markdown')) { typeHintsProvider.updateTypeHints(currentEditor); } } } function deactivate() {} module.exports = { activate, deactivate };