Show me more
This commit is contained in:
@@ -5,10 +5,11 @@ A Visual Studio Code extension that provides syntax highlighting and IntelliSens
|
||||
## Features
|
||||
|
||||
- **Syntax Highlighting**: Full syntax highlighting for ASHES language files (.esc)
|
||||
- **Auto-completion**: IntelliSense for ASHES commands, built-in variables, and keywords
|
||||
- **Hover Information**: Detailed information about commands and variables on hover
|
||||
- **Auto-completion**: IntelliSense for ASHES commands, built-in variables, and keywords with enhanced parameter information
|
||||
- **Hover Information**: Detailed information about commands and variables on hover with clear parameter indicators (required/optional, type, variable name)
|
||||
- **Go to Definition**: Ctrl+click on any command to navigate to its source file
|
||||
- **Code Snippets**: Pre-built snippets for common ASHES patterns
|
||||
- **Command Reference**: Built-in command reference panel
|
||||
- **Command Reference**: Built-in command reference panel with clickable command names
|
||||
- **Smart Indentation**: Proper indentation rules for ASHES code structure
|
||||
- **Dynamic Command Generation**: Automatically discovers and loads commands from your project's `project.godot` configuration - [Learn more about dynamic commands](DYNAMIC_COMMANDS.md)
|
||||
|
||||
@@ -21,7 +22,11 @@ A Visual Studio Code extension that provides syntax highlighting and IntelliSens
|
||||
### Commands
|
||||
- All standard Escoria commands (say, set_global, change_scene, etc.)
|
||||
- Custom commands
|
||||
- Command parameter hints
|
||||
- Enhanced command parameter hints with:
|
||||
- **Required** / **Optional** indicators
|
||||
- Parameter types (string, boolean, number, object, scene, animation, etc.)
|
||||
- Variable names in bold
|
||||
- Default values when available
|
||||
|
||||
### Variables
|
||||
- Local variables with `var`
|
||||
@@ -55,6 +60,10 @@ A Visual Studio Code extension that provides syntax highlighting and IntelliSens
|
||||
- Use `$` prefix for global ID suggestions
|
||||
- Built-in variables are automatically suggested
|
||||
|
||||
### Go to Definition
|
||||
- Ctrl+click on any command name in `.esc` files to navigate to its source file
|
||||
- Works in both the editor and the command reference panel
|
||||
|
||||
### Snippets
|
||||
- Type snippet prefixes and press `Tab` to expand:
|
||||
- `event` - Create new event
|
||||
@@ -65,7 +74,9 @@ A Visual Studio Code extension that provides syntax highlighting and IntelliSens
|
||||
|
||||
### Command Reference
|
||||
- Press `Ctrl+Shift+P` and type "ASHES: Show Command Reference"
|
||||
- View all available commands with descriptions and parameters
|
||||
- View all available commands with descriptions and enhanced parameter information
|
||||
- Parameters show clear indicators: **Required** / **Optional**, type, variable name, and default values
|
||||
- Click on any command name to navigate to its source file
|
||||
|
||||
## Language Features
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ export interface CommandInfo {
|
||||
description: string;
|
||||
parameters: CommandParameter[];
|
||||
example?: string;
|
||||
filePath?: string;
|
||||
}
|
||||
|
||||
export class CommandParser {
|
||||
@@ -103,6 +104,7 @@ export class CommandParser {
|
||||
let description = '';
|
||||
let parameters: CommandParameter[] = [];
|
||||
let example = '';
|
||||
let signatureParams: string[] = [];
|
||||
|
||||
let inParametersSection = false;
|
||||
let inExampleSection = false;
|
||||
@@ -116,12 +118,21 @@ export class CommandParser {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Extract main description (first comment block)
|
||||
// Extract main description (first comment block) and parameter names from signature
|
||||
if (line.startsWith('# `') && line.includes('`')) {
|
||||
const match = line.match(/# `([^`]+)`/);
|
||||
if (match) {
|
||||
description = match[1];
|
||||
description = match[1] + '\n\n';
|
||||
foundFirstDescription = true;
|
||||
|
||||
// Extract parameter names from command signature
|
||||
// e.g., "anim object name [reverse]" -> ["object", "name", "reverse"]
|
||||
const signature = match[1];
|
||||
const paramMatches = signature.match(/\b\w+\b/g);
|
||||
if (paramMatches && paramMatches.length > 1) {
|
||||
// Skip the first match (command name) and extract parameter names
|
||||
signatureParams = paramMatches.slice(1);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -142,7 +153,7 @@ export class CommandParser {
|
||||
|
||||
// If we haven't found the first description yet, this might be it
|
||||
if (!foundFirstDescription && cleanLine) {
|
||||
description = cleanLine;
|
||||
description += cleanLine;
|
||||
foundFirstDescription = true;
|
||||
continue;
|
||||
}
|
||||
@@ -155,7 +166,7 @@ export class CommandParser {
|
||||
cleanLine.includes('Run the command') || cleanLine.includes('Function called when')) {
|
||||
break;
|
||||
}
|
||||
description += ' ' + cleanLine;
|
||||
description += '\n' + cleanLine;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -195,12 +206,21 @@ export class CommandParser {
|
||||
defaultValue = defaultMatch[1].trim();
|
||||
}
|
||||
|
||||
// Determine parameter type from description
|
||||
// Determine parameter type from description with more comprehensive detection
|
||||
let paramType = 'string';
|
||||
if (paramDesc.includes('boolean') || paramDesc.includes('true') || paramDesc.includes('false')) {
|
||||
const descLower = paramDesc.toLowerCase();
|
||||
if (descLower.includes('boolean') || descLower.includes('true') || descLower.includes('false') ||
|
||||
descLower.includes('bool') || descLower.includes('flag')) {
|
||||
paramType = 'boolean';
|
||||
} else if (paramDesc.includes('number') || paramDesc.includes('int') || paramDesc.includes('float')) {
|
||||
} else if (descLower.includes('number') || descLower.includes('int') || descLower.includes('float') ||
|
||||
descLower.includes('integer') || descLower.includes('numeric')) {
|
||||
paramType = 'number';
|
||||
} else if (descLower.includes('object') || descLower.includes('node') || descLower.includes('item')) {
|
||||
paramType = 'object';
|
||||
} else if (descLower.includes('scene') || descLower.includes('room')) {
|
||||
paramType = 'scene';
|
||||
} else if (descLower.includes('animation') || descLower.includes('anim')) {
|
||||
paramType = 'animation';
|
||||
}
|
||||
|
||||
parameters.push({
|
||||
@@ -219,10 +239,18 @@ export class CommandParser {
|
||||
for (let j = i + 1; j < Math.min(i + 15, lines.length); j++) {
|
||||
const configLine = lines[j].trim();
|
||||
if (configLine.includes('ESCCommandArgumentDescriptor.new(')) {
|
||||
// Parse the descriptor parameters
|
||||
const descriptorMatch = configLine.match(/ESCCommandArgumentDescriptor\.new\(\s*(\d+)/);
|
||||
if (descriptorMatch) {
|
||||
const minArgs = parseInt(descriptorMatch[1]);
|
||||
// Parse the descriptor parameters - look for the number on the next line
|
||||
let minArgs = 0;
|
||||
for (let k = j + 1; k < Math.min(j + 5, lines.length); k++) {
|
||||
const nextLine = lines[k].trim();
|
||||
const numberMatch = nextLine.match(/^(\d+),?$/);
|
||||
if (numberMatch) {
|
||||
minArgs = parseInt(numberMatch[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (minArgs > 0) {
|
||||
|
||||
// Look for type arrays, defaults, and required flags in subsequent lines
|
||||
let types: string[] = [];
|
||||
@@ -240,16 +268,17 @@ export class CommandParser {
|
||||
}
|
||||
}
|
||||
|
||||
// Extract defaults array
|
||||
if (typeLine.includes('null') && typeLine.includes('[') && !typeLine.includes('TYPE_')) {
|
||||
// Extract defaults array (first array that doesn't contain TYPE_)
|
||||
if (typeLine.includes('[') && !typeLine.includes('TYPE_') && !defaults.length) {
|
||||
const defaultMatch = typeLine.match(/\[([^\]]+)\]/);
|
||||
if (defaultMatch) {
|
||||
defaults = defaultMatch[1].split(',').map(d => d.trim());
|
||||
}
|
||||
}
|
||||
|
||||
// Extract required flags array (look for true/false pattern)
|
||||
if (typeLine.includes('true') && typeLine.includes('false') && typeLine.includes('[') && !typeLine.includes('TYPE_')) {
|
||||
// Extract required flags array (second array that doesn't contain TYPE_ and has true/false)
|
||||
if (typeLine.includes('[') && !typeLine.includes('TYPE_') && defaults.length > 0 &&
|
||||
(typeLine.includes('true') || typeLine.includes('false'))) {
|
||||
const requiredMatch = typeLine.match(/\[([^\]]+)\]/);
|
||||
if (requiredMatch) {
|
||||
requiredFlags = requiredMatch[1].split(',').map(f => f.trim() === 'true');
|
||||
@@ -264,13 +293,16 @@ export class CommandParser {
|
||||
// Store original parameters from comments for name preservation
|
||||
const originalParams = [...parameters];
|
||||
|
||||
for (let p = 0; p < maxParams; p++) {
|
||||
// Use the total number of types, not just minArgs
|
||||
const totalParams = types.length;
|
||||
|
||||
for (let p = 0; p < totalParams; p++) {
|
||||
const type = types[p] || 'TYPE_STRING';
|
||||
const defaultValue = defaults[p] || 'null';
|
||||
// If requiredFlags array is not provided, use minArgs to determine required parameters
|
||||
const isRequired = p < minArgs || (requiredFlags[p] !== undefined ? requiredFlags[p] : p < minArgs);
|
||||
|
||||
// Convert Godot types to readable types
|
||||
// Convert Godot types to readable types with more comprehensive mapping
|
||||
let paramType = 'string';
|
||||
if (type.includes('TYPE_BOOL')) {
|
||||
paramType = 'boolean';
|
||||
@@ -278,12 +310,24 @@ export class CommandParser {
|
||||
paramType = 'number';
|
||||
} else if (type.includes('TYPE_STRING')) {
|
||||
paramType = 'string';
|
||||
} else if (type.includes('TYPE_VECTOR2')) {
|
||||
paramType = 'vector2';
|
||||
} else if (type.includes('TYPE_VECTOR3')) {
|
||||
paramType = 'vector3';
|
||||
} else if (type.includes('TYPE_ARRAY')) {
|
||||
paramType = 'array';
|
||||
} else if (type.includes('TYPE_DICTIONARY')) {
|
||||
paramType = 'dictionary';
|
||||
} else if (type.includes('TYPE_OBJECT')) {
|
||||
paramType = 'object';
|
||||
}
|
||||
|
||||
// Try to get parameter name from comments if available, otherwise generate one
|
||||
// Try to get parameter name from comments if available, otherwise use signature or generate one
|
||||
let paramName = `param${p + 1}`;
|
||||
if (p < originalParams.length && originalParams[p] && originalParams[p].name !== `param${p + 1}`) {
|
||||
if (p < originalParams.length && originalParams[p] && originalParams[p].name) {
|
||||
paramName = originalParams[p].name;
|
||||
} else if (p < signatureParams.length && signatureParams[p]) {
|
||||
paramName = signatureParams[p];
|
||||
}
|
||||
|
||||
newParameters.push({
|
||||
@@ -311,8 +355,10 @@ export class CommandParser {
|
||||
if (configureMatch) {
|
||||
const paramCount = parseInt(configureMatch[1]);
|
||||
for (let i = 0; i < paramCount; i++) {
|
||||
// Use signature parameter name if available, otherwise generate one
|
||||
const paramName = i < signatureParams.length ? signatureParams[i] : `param${i + 1}`;
|
||||
parameters.push({
|
||||
name: `param${i + 1}`,
|
||||
name: paramName,
|
||||
type: 'string',
|
||||
required: true
|
||||
});
|
||||
@@ -324,8 +370,8 @@ export class CommandParser {
|
||||
if (description) {
|
||||
description = description.trim();
|
||||
|
||||
// Remove extra whitespace
|
||||
description = description.replace(/\s+/g, ' ');
|
||||
// Remove extra whitespace but preserve newlines
|
||||
description = description.replace(/[ \t]+/g, ' ').replace(/\n\s+/g, '\n');
|
||||
|
||||
// Truncate if too long (keep first sentence or first 200 chars)
|
||||
const firstSentence = description.split('.')[0];
|
||||
@@ -345,7 +391,8 @@ export class CommandParser {
|
||||
name: commandName,
|
||||
description: description || `${commandName} command`,
|
||||
parameters: parameters,
|
||||
example: example
|
||||
example: example,
|
||||
filePath: filePath
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
@@ -395,13 +442,14 @@ export class CommandParser {
|
||||
/**
|
||||
* Get commands in the format expected by the VSCode extension
|
||||
*/
|
||||
public getCommandsForExtension(): Array<{name: string, description: string, parameters: CommandParameter[]}> {
|
||||
public getCommandsForExtension(): Array<{name: string, description: string, parameters: CommandParameter[], filePath?: string}> {
|
||||
const commands = this.parseCommands();
|
||||
|
||||
return commands.map(cmd => ({
|
||||
name: cmd.name,
|
||||
description: cmd.description,
|
||||
parameters: cmd.parameters
|
||||
parameters: cmd.parameters,
|
||||
filePath: cmd.filePath
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# Test ASHES file for the VSCode extension
|
||||
|
||||
# Test some commands
|
||||
say player "Hello world!"
|
||||
walk player target
|
||||
set_global test_var 42
|
||||
play_snd "sound.ogg" sfx
|
||||
Reference in New Issue
Block a user