Show me more

This commit is contained in:
2025-09-07 02:45:51 +02:00
parent 11a7724c58
commit 9c2a6cb7e7
4 changed files with 267 additions and 63 deletions

View File

@@ -3,7 +3,7 @@ import * as path from 'path';
import { CommandParser, CommandInfo, CommandParameter } from './commandParser';
// Cache for dynamically loaded commands
let ASHES_COMMANDS: Array<{name: string, description: string, parameters: CommandParameter[]}> = [];
let ASHES_COMMANDS: Array<{name: string, description: string, parameters: CommandParameter[], filePath?: string}> = [];
let COMMAND_CACHE_TIMESTAMP = 0;
// Built-in variables
@@ -24,7 +24,7 @@ const KEYWORDS = [
/**
* Load commands dynamically from the project
*/
function loadCommands(workspaceRoot: string): Array<{name: string, description: string, parameters: CommandParameter[]}> {
function loadCommands(workspaceRoot: string): Array<{name: string, description: string, parameters: CommandParameter[], filePath?: string}> {
try {
const parser = new CommandParser(workspaceRoot);
const commands = parser.getCommandsForExtension();
@@ -43,7 +43,7 @@ function loadCommands(workspaceRoot: string): Array<{name: string, description:
/**
* Get commands, using cache if available and not too old
*/
function getCommands(workspaceRoot: string): Array<{name: string, description: string, parameters: CommandParameter[]}> {
function getCommands(workspaceRoot: string): Array<{name: string, description: string, parameters: CommandParameter[], filePath?: string}> {
const now = Date.now();
const cacheAge = now - COMMAND_CACHE_TIMESTAMP;
const maxCacheAge = 5 * 60 * 1000; // 5 minutes
@@ -89,12 +89,15 @@ export function activate(context: vscode.ExtensionContext) {
const exampleParams: string[] = [];
command.parameters.forEach((param, index) => {
const required = param.required ? '**' : '';
const optional = param.required ? '' : ' (optional)';
const defaultValue = param.defaultValue ? ` (default: ${param.defaultValue})` : '';
paramDocs += `- ${required}${param.name}${required} (${param.type})${optional}${defaultValue}\n`;
// Enhanced parameter formatting with clear indicators
const requiredIndicator = param.required ? '**Required**' : '**Optional**';
const typeIndicator = `\`${param.type}\``;
const nameIndicator = `**${param.name}**`;
const defaultValue = param.defaultValue ? ` *(default: \`${param.defaultValue}\`)*` : '';
// Create example parameter
paramDocs += `- ${requiredIndicator} ${nameIndicator} (${typeIndicator})${defaultValue}\n`;
// Create example parameter with clear formatting
const exampleParam = param.required ?
`${param.name}: ${param.type}` :
`[${param.name}: ${param.type}]`;
@@ -163,12 +166,15 @@ export function activate(context: vscode.ExtensionContext) {
const exampleParams: string[] = [];
command.parameters.forEach((param, index) => {
const required = param.required ? '**' : '';
const optional = param.required ? '' : ' (optional)';
const defaultValue = param.defaultValue ? ` (default: ${param.defaultValue})` : '';
paramDocs += `- ${required}${param.name}${required} (${param.type})${optional}${defaultValue}\n`;
// Enhanced parameter formatting with clear indicators
const requiredIndicator = param.required ? '**Required**' : '**Optional**';
const typeIndicator = `\`${param.type}\``;
const nameIndicator = `**${param.name}**`;
const defaultValue = param.defaultValue ? ` *(default: \`${param.defaultValue}\`)*` : '';
// Create example parameter
paramDocs += `- ${requiredIndicator} ${nameIndicator} (${typeIndicator})${defaultValue}\n`;
// Create example parameter with clear formatting
const exampleParam = param.required ?
`${param.name}: ${param.type}` :
`[${param.name}: ${param.type}]`;
@@ -200,13 +206,64 @@ export function activate(context: vscode.ExtensionContext) {
}
);
// Register definition provider for Ctrl+click navigation
const definitionProvider = vscode.languages.registerDefinitionProvider(
'ashes',
{
provideDefinition(document: vscode.TextDocument, position: vscode.Position) {
const word = document.getText(document.getWordRangeAtPosition(position));
// Get workspace root
const workspaceRoot = vscode.workspace.getWorkspaceFolder(document.uri)?.uri.fsPath;
if (!workspaceRoot) {
return null;
}
// Get dynamic commands
const commands = getCommands(workspaceRoot);
const command = commands.find(cmd => cmd.name === word);
if (command && command.filePath) {
// Create a location pointing to the command file
const uri = vscode.Uri.file(command.filePath);
// Try to find the class definition line in the file
try {
const fs = require('fs');
const content = fs.readFileSync(command.filePath, 'utf8');
const lines = content.split('\n');
// Look for the class definition line
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (line.includes('class_name') && line.includes(command.name)) {
return new vscode.Location(uri, new vscode.Position(i, 0));
}
}
// If no class definition found, return the beginning of the file
return new vscode.Location(uri, new vscode.Position(0, 0));
} catch (error) {
console.error('Error reading command file:', error);
return new vscode.Location(uri, new vscode.Position(0, 0));
}
}
return null;
}
}
);
// Register command for showing command reference
const showCommandReference = vscode.commands.registerCommand('ashes.showCommandReference', () => {
const panel = vscode.window.createWebviewPanel(
'ashesCommandReference',
'ASHES Command Reference',
vscode.ViewColumn.One,
{}
{
enableScripts: true,
retainContextWhenHidden: true
}
);
// Get workspace root from active editor
@@ -236,6 +293,48 @@ export function activate(context: vscode.ExtensionContext) {
// Get dynamic commands
const commands = getCommands(workspaceRoot);
// Handle messages from the webview
panel.webview.onDidReceiveMessage(
message => {
switch (message.command) {
case 'navigateToCommand':
if (message.commandName && workspaceRoot) {
const command = commands.find(cmd => cmd.name === message.commandName);
if (command && command.filePath) {
const uri = vscode.Uri.file(command.filePath);
// Try to find the class definition line
try {
const fs = require('fs');
const content = fs.readFileSync(command.filePath, 'utf8');
const lines = content.split('\n');
// Look for the class definition line
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (line.includes('class_name') && line.includes(command.name)) {
vscode.window.showTextDocument(uri, {
selection: new vscode.Range(i, 0, i, 0)
});
return;
}
}
// If no class definition found, open at the beginning
vscode.window.showTextDocument(uri);
} catch (error) {
console.error('Error opening command file:', error);
vscode.window.showTextDocument(uri);
}
}
}
return;
}
},
undefined,
context.subscriptions
);
const commandsHtml = commands.map(command => {
let paramInfo = '';
let exampleUsage = '';
@@ -244,10 +343,11 @@ export function activate(context: vscode.ExtensionContext) {
const exampleParams: string[] = [];
paramInfo = command.parameters.map(param => {
const required = param.required ? '<strong>' : '';
const requiredEnd = param.required ? '</strong>' : '';
const optional = param.required ? '' : ' (optional)';
const defaultValue = param.defaultValue ? ` (default: ${param.defaultValue})` : '';
// Enhanced parameter formatting with clear indicators
const requiredIndicator = param.required ? '<strong>Required</strong>' : '<strong>Optional</strong>';
const typeIndicator = `<code>${param.type}</code>`;
const nameIndicator = `<strong>${param.name}</strong>`;
const defaultValue = param.defaultValue ? ` <em>(default: <code>${param.defaultValue}</code>)</em>` : '';
// Create example parameter
const exampleParam = param.required ?
@@ -255,7 +355,7 @@ export function activate(context: vscode.ExtensionContext) {
`[${param.name}: ${param.type}]`;
exampleParams.push(exampleParam);
return `${required}${param.name}${requiredEnd} (${param.type})${optional}${defaultValue}`;
return `${requiredIndicator} ${nameIndicator} (${typeIndicator})${defaultValue}`;
}).join('<br>');
// Create example usage
@@ -263,7 +363,7 @@ export function activate(context: vscode.ExtensionContext) {
}
return `<tr>
<td><code>${command.name}</code></td>
<td><code class="command-link" data-command="${command.name}">${command.name}</code></td>
<td>${command.description}${exampleUsage}</td>
<td>${paramInfo}</td>
</tr>`;
@@ -274,15 +374,47 @@ export function activate(context: vscode.ExtensionContext) {
<html>
<head>
<style>
body { font-family: var(--vscode-font-family); }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid var(--vscode-panel-border); padding: 8px; text-align: left; }
th { background-color: var(--vscode-panel-background); }
code { background-color: var(--vscode-textCodeBlock-background); padding: 2px 4px; }
body {
font-family: var(--vscode-font-family);
margin: 20px;
}
table {
border-collapse: collapse;
width: 100%;
}
th, td {
border: 1px solid var(--vscode-panel-border);
padding: 8px;
text-align: left;
}
th {
background-color: var(--vscode-panel-background);
}
code {
background-color: var(--vscode-textCodeBlock-background);
padding: 2px 4px;
}
.command-link {
cursor: pointer;
color: var(--vscode-textLink-foreground);
text-decoration: underline;
}
.command-link:hover {
color: var(--vscode-textLink-activeForeground);
}
.info {
margin-bottom: 20px;
padding: 10px;
background-color: var(--vscode-textBlockQuote-background);
border-left: 4px solid var(--vscode-textBlockQuote-border);
}
</style>
</head>
<body>
<h1>ASHES Command Reference</h1>
<div class="info">
💡 <strong>Tip:</strong> Click on any command name to navigate to its source file!
</div>
<table>
<thead>
<tr>
@@ -295,6 +427,26 @@ export function activate(context: vscode.ExtensionContext) {
${commandsHtml}
</tbody>
</table>
<script>
const vscode = acquireVsCodeApi();
// Add click handlers to all command links
document.addEventListener('DOMContentLoaded', function() {
const commandLinks = document.querySelectorAll('.command-link');
commandLinks.forEach(link => {
link.addEventListener('click', function() {
const commandName = this.getAttribute('data-command');
if (commandName) {
vscode.postMessage({
command: 'navigateToCommand',
commandName: commandName
});
}
});
});
});
</script>
</body>
</html>
`;
@@ -309,7 +461,7 @@ export function activate(context: vscode.ExtensionContext) {
vscode.window.showInformationMessage('ASHES commands cache refreshed!');
});
context.subscriptions.push(completionProvider, hoverProvider, showCommandReference, refreshCommands);
context.subscriptions.push(completionProvider, hoverProvider, definitionProvider, showCommandReference, refreshCommands);
}
export function deactivate() {}