Extension init, syntax highlighting, autocompletion, install script

This commit is contained in:
2025-09-07 01:47:30 +02:00
parent e580db794d
commit 7479320aab
15 changed files with 1708 additions and 1 deletions

View File

@@ -1,5 +1,6 @@
{
"editor.tabSize": 4,
"editor.insertSpaces": false,
"editor.detectIndentation": false
"editor.detectIndentation": false,
"godotTools.editorPath.godot4": "/home/oier/Descargas/Godot_v4.4.1-stable_linux.x86_64"
}

171
install-extension.sh Executable file
View File

@@ -0,0 +1,171 @@
#!/bin/bash
# ASHES Language Support Extension Installer
# This script installs the ASHES language support extension for VSCode/VSCodium
set -e # Exit on any error
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Function to print colored output
print_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
print_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Function to detect VSCode/VSCodium extensions directory
detect_extensions_dir() {
local extensions_dir=""
# Check for VSCodium first (more common on Linux)
if command -v codium &> /dev/null; then
extensions_dir="$HOME/.vscode-oss/extensions"
elif command -v code &> /dev/null; then
extensions_dir="$HOME/.vscode/extensions"
else
print_warning "Neither VSCode nor VSCodium found in PATH"
extensions_dir="$HOME/.vscode/extensions"
fi
echo "$extensions_dir"
}
# Function to check if directory exists and is writable
check_directory() {
local dir="$1"
if [ ! -d "$dir" ]; then
print_info "Creating directory: $dir"
mkdir -p "$dir" || {
print_error "Failed to create directory: $dir"
return 1
}
fi
if [ ! -w "$dir" ]; then
print_error "Directory is not writable: $dir"
return 1
fi
return 0
}
# Main installation function
main() {
print_info "ASHES Language Support Extension Installer"
print_info "=========================================="
echo
# Get the script directory (where the vscode-extension folder is located)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
EXTENSION_SOURCE="$SCRIPT_DIR/vscode-extension-ashes"
# Check if source extension directory exists
if [ ! -d "$EXTENSION_SOURCE" ]; then
print_error "Extension source directory not found: $EXTENSION_SOURCE"
print_error "Please run this script from the project root directory."
exit 1
fi
# Detect default extensions directory
DEFAULT_EXTENSIONS_DIR=$(detect_extensions_dir)
print_info "Default VSCode/VSCodium extensions directory:"
print_info " $DEFAULT_EXTENSIONS_DIR"
echo
# Ask for confirmation or custom path
read -p "Use default path? (y/n) [y]: " use_default
use_default=${use_default:-y}
if [[ $use_default =~ ^[Yy]$ ]]; then
EXTENSIONS_DIR="$DEFAULT_EXTENSIONS_DIR"
else
echo
read -p "Enter custom extensions directory path: " custom_path
EXTENSIONS_DIR="$custom_path"
fi
# Validate the extensions directory
if ! check_directory "$EXTENSIONS_DIR"; then
exit 1
fi
# Set the destination path for the symlink
EXTENSION_DEST="$EXTENSIONS_DIR/vscode-extension-ashes"
echo
print_info "Installation Summary:"
print_info "===================="
print_info "Source: $EXTENSION_SOURCE"
print_info "Destination: $EXTENSION_DEST"
print_info "Link name: vscode-extension-ashes"
echo
# Final confirmation
read -p "Proceed with installation? (y/n) [y]: " confirm
confirm=${confirm:-y}
if [[ ! $confirm =~ ^[Yy]$ ]]; then
print_info "Installation cancelled."
exit 0
fi
echo
print_info "Installing extension..."
# Check if destination already exists
if [ -e "$EXTENSION_DEST" ]; then
print_warning "Destination already exists: $EXTENSION_DEST"
read -p "Remove existing installation? (y/n) [y]: " remove_existing
remove_existing=${remove_existing:-y}
if [[ $remove_existing =~ ^[Yy]$ ]]; then
print_info "Removing existing installation..."
rm -rf "$EXTENSION_DEST" || {
print_error "Failed to remove existing installation"
exit 1
}
else
print_info "Installation cancelled."
exit 0
fi
fi
# Create the symlink
print_info "Creating symlink..."
if ln -s "$EXTENSION_SOURCE" "$EXTENSION_DEST"; then
print_success "Extension installed successfully!"
echo
print_info "Next steps:"
print_info "1. Restart VSCode/VSCodium"
print_info "2. Open any .esc file to test the extension"
print_info "3. The language should be automatically detected as 'ASHES'"
echo
print_info "To uninstall, simply remove the symlink:"
print_info " rm '$EXTENSION_DEST'"
else
print_error "Failed to create symlink"
print_error "Make sure you have write permissions to: $EXTENSIONS_DIR"
exit 1
fi
}
# Run main function
main "$@"

4
vscode-extension-ashes/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
out
node_modules
*.vsix
.DS_Store

View File

@@ -0,0 +1,10 @@
.vscode/**
.vscode-test/**
src/**
.gitignore
.yarnrc
vsc-extension-quickstart.md
**/tsconfig.json
**/.eslintrc.json
**/*.map
**/*.ts

View File

@@ -0,0 +1,84 @@
# Installation Guide for ASHES Language Support Extension
## Quick Installation
1. **Copy the extension folder** to your VS Code extensions directory:
- **Linux**: `~/.vscode/extensions/`
- **macOS**: `~/.vscode/extensions/`
- **Windows**: `%USERPROFILE%\.vscode\extensions\`
2. **Rename the folder** to `ashes-language-support-0.1.0` (or similar)
3. **Reload VS Code** or restart the application
4. **Test the extension** by opening any `.esc` file
## Alternative Installation (Development Mode)
1. **Open VS Code** in the extension directory:
```bash
cd vscode-extension
code .
```
2. **Press F5** to run the extension in a new Extension Development Host window
3. **Open a .esc file** in the new window to test the extension
## Building from Source
1. **Install dependencies**:
```bash
npm install
```
2. **Compile TypeScript**:
```bash
npm run compile
```
3. **Package the extension** (optional):
```bash
npx vsce package
```
## Testing the Extension
1. **Open the sample file**: `sample.esc` in the extension directory
2. **Check syntax highlighting**: Events, commands, and variables should be colorized
3. **Test auto-completion**: Type `say(` and press `Ctrl+Space`
4. **Test snippets**: Type `event` and press `Tab`
5. **Test hover**: Hover over commands like `say` or `set_global`
6. **Test command reference**: Press `Ctrl+Shift+P` and type "ASHES: Show Command Reference"
## Features to Test
- ✅ Syntax highlighting for events (`:event_name`)
- ✅ Syntax highlighting for commands (`say`, `set_global`, etc.)
- ✅ Syntax highlighting for variables (`var`, `global`)
- ✅ Syntax highlighting for dialog blocks (`?!`)
- ✅ Auto-completion for commands
- ✅ Auto-completion for built-in variables
- ✅ Code snippets for common patterns
- ✅ Hover information for commands
- ✅ Smart indentation
- ✅ Code folding for events
## Troubleshooting
### Extension not loading
- Check that the folder is in the correct extensions directory
- Restart VS Code completely
- Check the Developer Console for errors (`Help > Toggle Developer Tools`)
### Syntax highlighting not working
- Make sure the file has a `.esc` extension
- Check that the language is set to "ASHES" in the bottom-right corner of VS Code
### Auto-completion not working
- Press `Ctrl+Space` to manually trigger completion
- Check that the extension is activated (should show in the Extensions panel)
## Uninstalling
Simply delete the extension folder from your VS Code extensions directory and restart VS Code.

View File

@@ -0,0 +1,93 @@
# ASHES Language Support
A Visual Studio Code extension that provides syntax highlighting and IntelliSense for the ASHES (Adventure Scripting Helping Escoria) language used in Escoria adventure game framework.
## 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
- **Code Snippets**: Pre-built snippets for common ASHES patterns
- **Command Reference**: Built-in command reference panel
- **Smart Indentation**: Proper indentation rules for ASHES code structure
## ASHES Language Features Supported
### Events
- Event definitions with `:event_name`
- Event flags with `| FLAG_NAME`
### Commands
- All standard Escoria commands (say, set_global, change_scene, etc.)
- Custom commands
- Command parameter hints
### Variables
- Local variables with `var`
- Global variables with `global`
- Built-in variables (CURRENT_PLAYER, ESC_LAST_SCENE, etc.)
- Global IDs with `$` prefix
### Control Flow
- If/elif/else statements
- While loops
- Break and done keywords
### Dialog System
- Dialog blocks with `?!`
- Dialog choices with `-`
- Conditional dialog choices with `[condition]`
### Comments
- Line comments with `#`
## Installation
1. Copy this extension folder to your VS Code extensions directory
2. Reload VS Code
3. Open any `.esc` file to see syntax highlighting
## Usage
### Auto-completion
- Type any ASHES command and press `Ctrl+Space` for suggestions
- Use `$` prefix for global ID suggestions
- Built-in variables are automatically suggested
### Snippets
- Type snippet prefixes and press `Tab` to expand:
- `event` - Create new event
- `say` - Say command
- `dialog` - Dialog block
- `if` - If statement
- And many more...
### Command Reference
- Press `Ctrl+Shift+P` and type "ASHES: Show Command Reference"
- View all available commands with descriptions and parameters
## Language Features
### Syntax Highlighting
- Events are highlighted in blue
- Commands are highlighted in green
- Variables are highlighted in orange
- Strings are highlighted in yellow
- Comments are highlighted in gray
- Dialog blocks have special highlighting
### Smart Indentation
- Automatic indentation for events, control flow, and dialog blocks
- Proper outdenting for `break`, `done`, `else`, etc.
### Folding
- Events can be folded for better code organization
- Dialog blocks can be folded
## Contributing
This extension is designed specifically for the Escoria framework and ASHES language. If you find issues or want to add features, please contribute to the project.
## License
This extension is part of the Gymkhana project and follows the same license terms.

View File

@@ -0,0 +1,35 @@
{
"comments": {
"lineComment": "#"
},
"brackets": [
["{", "}"],
["[", "]"],
["(", ")"]
],
"autoClosingPairs": [
["{", "}"],
["[", "]"],
["(", ")"],
["\"", "\""],
["'", "'"]
],
"surroundingPairs": [
["{", "}"],
["[", "]"],
["(", ")"],
["\"", "\""],
["'", "'"]
],
"folding": {
"markers": {
"start": "^\\s*:",
"end": "^\\s*$"
}
},
"wordPattern": "(-?\\d*\\.\\d\\w*)|([^\\`\\~\\!\\@\\#\\%\\^\\&\\*\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s]+)",
"indentationRules": {
"increaseIndentPattern": "^\\s*(?!\\s*#).*:\\s*$|^\\s*if\\s+.*:|^\\s*elif\\s+.*:|^\\s*else\\s*:|^\\s*while\\s+.*:|^\\s*-\\s+.*:|^\\s*\\?!\\s*$",
"decreaseIndentPattern": "^\\s*(elif|else|done|break|stop)\\b"
}
}

49
vscode-extension-ashes/package-lock.json generated Normal file
View File

@@ -0,0 +1,49 @@
{
"name": "ashes-language-support",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ashes-language-support",
"version": "0.1.0",
"license": "ISC",
"devDependencies": {
"@types/node": "16.x",
"@types/vscode": "^1.74.0",
"typescript": "^4.9.4"
},
"engines": {
"vscode": "^1.74.0"
}
},
"node_modules/@types/node": {
"version": "16.18.126",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.126.tgz",
"integrity": "sha512-OTcgaiwfGFBKacvfwuHzzn1KLxH/er8mluiy8/uM3sGXHaRe73RrSIj01jow9t4kJEW633Ov+cOexXeiApTyAw==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/vscode": {
"version": "1.103.0",
"resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.103.0.tgz",
"integrity": "sha512-o4hanZAQdNfsKecexq9L3eHICd0AAvdbLk6hA60UzGXbGH/q8b/9xv2RgR7vV3ZcHuyKVq7b37IGd/+gM4Tu+Q==",
"dev": true,
"license": "MIT"
},
"node_modules/typescript": {
"version": "4.9.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=4.2.0"
}
}
}
}

View File

@@ -0,0 +1,79 @@
{
"name": "ashes-language-support",
"displayName": "ASHES Language Support",
"description": "Syntax highlighting and IntelliSense for ASHES (Adventure Scripting Helping Escoria) language",
"version": "0.1.0",
"publisher": "gymkhana-dev",
"engines": {
"vscode": "^1.74.0"
},
"categories": [
"Programming Languages",
"Snippets"
],
"keywords": [
"ashes",
"escoria",
"adventure",
"game",
"scripting"
],
"activationEvents": [
"onLanguage:ashes"
],
"main": "./out/extension.js",
"contributes": {
"languages": [
{
"id": "ashes",
"aliases": [
"ASHES",
"ashes"
],
"extensions": [
".esc"
],
"configuration": "./language-configuration.json"
}
],
"grammars": [
{
"language": "ashes",
"scopeName": "source.ashes",
"path": "./syntaxes/ashes.tmLanguage.json"
}
],
"snippets": [
{
"language": "ashes",
"path": "./snippets/ashes.json"
}
],
"commands": [
{
"command": "ashes.showCommandReference",
"title": "Show ASHES Command Reference",
"category": "ASHES"
}
],
"menus": {
"commandPalette": [
{
"command": "ashes.showCommandReference"
}
]
}
},
"scripts": {
"vscode:prepublish": "npm run compile",
"compile": "tsc -p ./",
"watch": "tsc -watch -p ./"
},
"devDependencies": {
"@types/node": "16.x",
"@types/vscode": "^1.74.0",
"typescript": "^4.9.4"
},
"author": "",
"license": "ISC"
}

View File

@@ -0,0 +1,102 @@
# Sample ASHES script for testing the VS Code extension
# This file demonstrates various ASHES language features
:setup
# Global variable declarations
global game_started = false
global player_name = "Player"
global score = 0
# Local variables
var tutorial_completed = false
var current_room = "intro"
# Set initial state
set_global("game_started", true)
set_active($player, true)
teleport($player, $start_position)
:ready
# Check if this is the first time
if !game_started:
say($player, "Welcome to the game!", "welcome_message")
game_started = true
else:
say($player, "Welcome back!", "welcome_back")
:action1
# Simple interaction
say($player, "You examine the object carefully.", "examine_object")
# Check inventory
if $magic_key in inventory:
say($player, "You have the magic key!", "has_key")
else:
say($player, "You need a key to proceed.", "needs_key")
:action2
# Dialog system example
say($player, "You approach the mysterious character.", "approach_character")
?!
- "Hello, who are you?" [!name_known]
say_last_dialog_option()
say($npc, "I am the guardian of this place.", "guardian_intro")
global name_known = true
- "Can you help me?" [name_known]
say_last_dialog_option()
say($npc, "I can guide you, but you must prove yourself.", "guardian_help")
?!
- "How can I prove myself?"
say_last_dialog_option()
say($npc, "Find the three ancient artifacts.", "guardian_task")
- "I'm not interested."
say_last_dialog_option()
say($npc, "Very well, good luck on your own.", "guardian_dismiss")
done
- "Goodbye"
say_last_dialog_option()
say($npc, "Farewell, traveler.", "guardian_farewell")
done
:action3
# Complex logic example
var artifacts_found = 0
# Check for artifacts
if $artifact1_collected:
artifacts_found += 1
if $artifact2_collected:
artifacts_found += 1
if $artifact3_collected:
artifacts_found += 1
# Conditional responses
if artifacts_found == 3:
say($player, "I have found all three artifacts!", "all_artifacts")
change_scene("res://rooms/victory_room.tscn")
elif artifacts_found > 0:
say($player, "I have found " + str(artifacts_found) + " artifacts so far.", "some_artifacts")
else:
say($player, "I haven't found any artifacts yet.", "no_artifacts")
:use | TK
# Use with item
if $magic_key in inventory:
say($player, "You use the magic key.", "use_key")
set_active($locked_door, false)
play_snd("res://sounds/door_open.ogg", _sfx)
else:
say($player, "You can't use this without the right item.", "cant_use")
:look
# Look action
say($player, "You look around carefully.", "look_around")
# Conditional descriptions
if $secret_door is active:
say($player, "You notice a hidden passage.", "hidden_passage")
else:
say($player, "Nothing unusual catches your eye.", "nothing_unusual")
# End of sample script

View File

@@ -0,0 +1,176 @@
{
"Event": {
"prefix": "event",
"body": [
":${1:event_name}",
"\t${2:// Event code here}"
],
"description": "Create a new ASHES event"
},
"Event with target": {
"prefix": "eventtarget",
"body": [
":${1:event_name} \"${2:target_id}\"",
"\t${3:// Event code here}"
],
"description": "Create a new ASHES event with target"
},
"Event with flags": {
"prefix": "eventflags",
"body": [
":${1:event_name} | ${2:NO_UI} | ${3:NO_TT}",
"\t${4:// Event code here}"
],
"description": "Create a new ASHES event with flags"
},
"Event with flags and target": {
"prefix": "eventflagstarget",
"body": [
":${1:event_name} | ${2:NO_UI} | ${3:NO_TT} \"${4:target_id}\"",
"\t${5:// Event code here}"
],
"description": "Create a new ASHES event with flags and target"
},
"Say command": {
"prefix": "say",
"body": [
"say(${1:player}, \"${2:text}\"${3:, \"${4:translation_key}\"})"
],
"description": "Say command for dialog"
},
"Set global variable": {
"prefix": "setglobal",
"body": [
"set_global(\"${1:variable_name}\", ${2:value})"
],
"description": "Set a global variable"
},
"Global variable declaration": {
"prefix": "global",
"body": [
"global ${1:variable_name}${2: = ${3:value}}"
],
"description": "Declare a global variable"
},
"Local variable declaration": {
"prefix": "var",
"body": [
"var ${1:variable_name}${2: = ${3:value}}"
],
"description": "Declare a local variable"
},
"If statement": {
"prefix": "if",
"body": [
"if ${1:condition}:",
"\t${2:// Code here}"
],
"description": "If statement"
},
"If-else statement": {
"prefix": "ifelse",
"body": [
"if ${1:condition}:",
"\t${2:// Code here}",
"else:",
"\t${3:// Code here}"
],
"description": "If-else statement"
},
"While loop": {
"prefix": "while",
"body": [
"while ${1:condition}:",
"\t${2:// Code here}"
],
"description": "While loop"
},
"Dialog block": {
"prefix": "dialog",
"body": [
"?!",
"\t- \"${1:choice_text}\"",
"\t\t${2:// Code here}"
],
"description": "Dialog block with choice"
},
"Dialog choice with condition": {
"prefix": "dialogif",
"body": [
"?!",
"\t- \"${1:choice_text}\" [${2:condition}]",
"\t\t${3:// Code here}"
],
"description": "Dialog choice with condition"
},
"Change scene": {
"prefix": "changescene",
"body": [
"change_scene(\"${1:scene_path}\"${2:, ${3:true}})"
],
"description": "Change to a different scene"
},
"Set active": {
"prefix": "setactive",
"body": [
"set_active($${1:object_id}, ${2:true})"
],
"description": "Set object active/inactive"
},
"Teleport": {
"prefix": "teleport",
"body": [
"teleport($${1:object_id}, $${2:target_id})"
],
"description": "Teleport object to target"
},
"Walk to": {
"prefix": "walk",
"body": [
"walk($${1:object_id}, $${2:target_id})"
],
"description": "Walk object to target"
},
"Play sound": {
"prefix": "playsnd",
"body": [
"play_snd(\"${1:sound_path}\"${2:, ${3:_music}})"
],
"description": "Play a sound file"
},
"Play video": {
"prefix": "playvideo",
"body": [
"play_video(\"${1:video_path}\")"
],
"description": "Play a video file"
},
"Inventory add": {
"prefix": "inventoryadd",
"body": [
"inventory_add($${1:item_id})"
],
"description": "Add item to inventory"
},
"Inventory remove": {
"prefix": "inventoryremove",
"body": [
"inventory_remove($${1:item_id})"
],
"description": "Remove item from inventory"
},
"Comment": {
"prefix": "comment",
"body": [
"# ${1:comment}"
],
"description": "Add a comment"
},
"Print": {
"prefix": "print",
"body": [
"print(\"${1:message}\")"
],
"description": "Print debug message"
}
}

View File

@@ -0,0 +1,495 @@
import * as vscode from 'vscode';
// ASHES commands with their descriptions and parameters
const ASHES_COMMANDS = [
{
name: 'accept_input',
description: 'Accept specific input types',
parameters: ['input_type']
},
{
name: 'anim',
description: 'Play animation on object',
parameters: ['object_id', 'animation_name']
},
{
name: 'anim_block',
description: 'Play animation and wait for completion',
parameters: ['object_id', 'animation_name']
},
{
name: 'block_say',
description: 'Start a block of say commands',
parameters: []
},
{
name: 'camera_push',
description: 'Push camera to new position',
parameters: ['x', 'y']
},
{
name: 'camera_push_block',
description: 'Push camera and wait for completion',
parameters: ['x', 'y']
},
{
name: 'camera_set_limits',
description: 'Set camera movement limits',
parameters: ['left', 'top', 'right', 'bottom']
},
{
name: 'camera_set_pos',
description: 'Set camera position',
parameters: ['x', 'y']
},
{
name: 'camera_set_pos_block',
description: 'Set camera position and wait',
parameters: ['x', 'y']
},
{
name: 'camera_set_target',
description: 'Set camera target',
parameters: ['object_id']
},
{
name: 'camera_set_target_block',
description: 'Set camera target and wait',
parameters: ['object_id']
},
{
name: 'camera_set_zoom',
description: 'Set camera zoom level',
parameters: ['zoom_level']
},
{
name: 'camera_set_zoom_block',
description: 'Set camera zoom and wait',
parameters: ['zoom_level']
},
{
name: 'camera_set_zoom_height',
description: 'Set camera zoom height',
parameters: ['height']
},
{
name: 'camera_set_zoom_height_block',
description: 'Set camera zoom height and wait',
parameters: ['height']
},
{
name: 'camera_shift',
description: 'Shift camera position',
parameters: ['x', 'y']
},
{
name: 'camera_shift_block',
description: 'Shift camera and wait',
parameters: ['x', 'y']
},
{
name: 'change_scene',
description: 'Change to a different scene',
parameters: ['scene_path', 'enable_transition', 'run_events']
},
{
name: 'custom',
description: 'Execute custom command',
parameters: ['command_name', '...args']
},
{
name: 'dec_global',
description: 'Decrement global variable',
parameters: ['variable_name']
},
{
name: 'enable_terrain',
description: 'Enable/disable terrain',
parameters: ['terrain_name', 'enabled']
},
{
name: 'end_block_say',
description: 'End a block of say commands',
parameters: []
},
{
name: 'hide_menu',
description: 'Hide menu',
parameters: ['menu_name']
},
{
name: 'inc_global',
description: 'Increment global variable',
parameters: ['variable_name']
},
{
name: 'inventory_add',
description: 'Add item to inventory',
parameters: ['item_id']
},
{
name: 'inventory_remove',
description: 'Remove item from inventory',
parameters: ['item_id']
},
{
name: 'item_count_add',
description: 'Add to item count',
parameters: ['item_id', 'count']
},
{
name: 'play_lib_snd',
description: 'Play library sound',
parameters: ['filename', 'namespace']
},
{
name: 'play_snd',
description: 'Play sound file',
parameters: ['sound_path', 'type']
},
{
name: 'play_video',
description: 'Play video file',
parameters: ['video_path']
},
{
name: 'print',
description: 'Print debug message',
parameters: ['message']
},
{
name: 'print_internal',
description: 'Print internal message',
parameters: ['message']
},
{
name: 'queue_event',
description: 'Queue event for later execution',
parameters: ['object_id', 'event_name']
},
{
name: 'queue_resource',
description: 'Queue resource for loading',
parameters: ['resource_path']
},
{
name: 'rand_global',
description: 'Set random value to global',
parameters: ['variable_name', 'min', 'max']
},
{
name: 'repeat',
description: 'Repeat command',
parameters: ['count', 'command']
},
{
name: 'save_game',
description: 'Save game state',
parameters: ['save_name']
},
{
name: 'say',
description: 'Display dialog text',
parameters: ['speaker', 'text', 'translation_key', 'type']
},
{
name: 'say_last_dialog_option',
description: 'Say the last dialog option',
parameters: []
},
{
name: 'say_random',
description: 'Say random text from list',
parameters: ['speaker', 'list_id', 'length']
},
{
name: 'say_sequence',
description: 'Say text sequence',
parameters: ['speaker', 'list_id', 'length', 'loop']
},
{
name: 'sched_event',
description: 'Schedule event for later',
parameters: ['delay', 'object_id', 'event_name']
},
{
name: 'set_active',
description: 'Set object active/inactive',
parameters: ['object_id', 'active']
},
{
name: 'set_active_if_exists',
description: 'Set object active if it exists',
parameters: ['object_id', 'active']
},
{
name: 'set_angle',
description: 'Set object angle',
parameters: ['object_id', 'angle']
},
{
name: 'set_animations',
description: 'Set object animations',
parameters: ['object_id', 'animations']
},
{
name: 'set_direction',
description: 'Set object direction',
parameters: ['object_id', 'direction']
},
{
name: 'set_global',
description: 'Set global variable',
parameters: ['variable_name', 'value', 'force']
},
{
name: 'set_globals',
description: 'Set multiple global variables',
parameters: ['variables_dict']
},
{
name: 'set_gui_visible',
description: 'Set GUI visibility',
parameters: ['visible']
},
{
name: 'set_interactive',
description: 'Set object interactive state',
parameters: ['object_id', 'interactive']
},
{
name: 'set_item_custom_data',
description: 'Set item custom data',
parameters: ['item_id', 'key', 'value']
},
{
name: 'set_speed',
description: 'Set object speed',
parameters: ['object_id', 'speed']
},
{
name: 'set_state',
description: 'Set object state',
parameters: ['object_id', 'state']
},
{
name: 'set_tooltip',
description: 'Set object tooltip',
parameters: ['object_id', 'action', 'text']
},
{
name: 'show_menu',
description: 'Show menu',
parameters: ['menu_name']
},
{
name: 'slide',
description: 'Slide object to position',
parameters: ['object_id', 'x', 'y', 'duration']
},
{
name: 'slide_block',
description: 'Slide object and wait',
parameters: ['object_id', 'x', 'y', 'duration']
},
{
name: 'spawn',
description: 'Spawn object',
parameters: ['object_id', 'x', 'y']
},
{
name: 'stop',
description: 'Stop current event',
parameters: []
},
{
name: 'stop_snd',
description: 'Stop sound',
parameters: ['sound_type']
},
{
name: 'teleport',
description: 'Teleport object to target',
parameters: ['object_id', 'target_id']
},
{
name: 'teleport_pos',
description: 'Teleport object to position',
parameters: ['object_id', 'x', 'y']
},
{
name: 'transition',
description: 'Play transition effect',
parameters: ['transition_type', 'duration']
},
{
name: 'turn_to',
description: 'Turn object to face target',
parameters: ['object_id', 'target_id']
},
{
name: 'wait',
description: 'Wait for specified time',
parameters: ['duration']
},
{
name: 'walk',
description: 'Walk object to target',
parameters: ['object_id', 'target_id']
},
{
name: 'walk_block',
description: 'Walk object and wait',
parameters: ['object_id', 'target_id']
},
{
name: 'walk_to_pos',
description: 'Walk object to position',
parameters: ['object_id', 'x', 'y']
},
{
name: 'walk_to_pos_block',
description: 'Walk object to position and wait',
parameters: ['object_id', 'x', 'y']
}
];
// Built-in variables
const BUILTIN_VARIABLES = [
'CURRENT_PLAYER',
'ESC_LAST_SCENE',
'ESC_CURRENT_SCENE',
'FORCE_LAST_SCENE_NULL',
'ANIMATION_RESOURCES'
];
// Keywords
const KEYWORDS = [
'var', 'global', 'if', 'elif', 'else', 'while', 'break', 'done', 'stop', 'pass',
'true', 'false', 'nil', 'and', 'or', 'not', 'in', 'is', 'active'
];
export function activate(context: vscode.ExtensionContext) {
console.log('ASHES Language Support extension is now active!');
// Register completion provider
const completionProvider = vscode.languages.registerCompletionItemProvider(
'ashes',
{
provideCompletionItems(document: vscode.TextDocument, position: vscode.Position) {
const completions: vscode.CompletionItem[] = [];
// Add command completions
ASHES_COMMANDS.forEach(command => {
const completion = new vscode.CompletionItem(command.name, vscode.CompletionItemKind.Function);
completion.detail = command.description;
completion.documentation = new vscode.MarkdownString(
`**${command.name}**\n\n${command.description}\n\n**Parameters:** ${command.parameters.join(', ')}`
);
completion.insertText = new vscode.SnippetString(`${command.name}($1)`);
completions.push(completion);
});
// Add built-in variable completions
BUILTIN_VARIABLES.forEach(variable => {
const completion = new vscode.CompletionItem(variable, vscode.CompletionItemKind.Variable);
completion.detail = 'Built-in variable';
completion.documentation = new vscode.MarkdownString(`Built-in ASHES variable: **${variable}**`);
completions.push(completion);
});
// Add keyword completions
KEYWORDS.forEach(keyword => {
const completion = new vscode.CompletionItem(keyword, vscode.CompletionItemKind.Keyword);
completion.detail = 'ASHES keyword';
completions.push(completion);
});
return completions;
}
},
' ', '(', '$' // Trigger characters
);
// Register hover provider for commands
const hoverProvider = vscode.languages.registerHoverProvider(
'ashes',
{
provideHover(document: vscode.TextDocument, position: vscode.Position) {
const word = document.getText(document.getWordRangeAtPosition(position));
const command = ASHES_COMMANDS.find(cmd => cmd.name === word);
if (command) {
const hover = new vscode.Hover(
new vscode.MarkdownString(
`**${command.name}**\n\n${command.description}\n\n**Parameters:** ${command.parameters.join(', ')}`
)
);
return hover;
}
const builtinVar = BUILTIN_VARIABLES.find(variable => variable === word);
if (builtinVar) {
const hover = new vscode.Hover(
new vscode.MarkdownString(`Built-in ASHES variable: **${builtinVar}**`)
);
return hover;
}
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,
{}
);
const commandsHtml = ASHES_COMMANDS.map(command =>
`<tr>
<td><code>${command.name}</code></td>
<td>${command.description}</td>
<td><code>${command.parameters.join(', ')}</code></td>
</tr>`
).join('');
panel.webview.html = `
<!DOCTYPE html>
<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; }
</style>
</head>
<body>
<h1>ASHES Command Reference</h1>
<table>
<thead>
<tr>
<th>Command</th>
<th>Description</th>
<th>Parameters</th>
</tr>
</thead>
<tbody>
${commandsHtml}
</tbody>
</table>
</body>
</html>
`;
});
context.subscriptions.push(completionProvider, hoverProvider, showCommandReference);
}
export function deactivate() {}

View File

@@ -0,0 +1,390 @@
{
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": "ASHES",
"scopeName": "source.ashes",
"patterns": [
{
"include": "#comments"
},
{
"include": "#events"
},
{
"include": "#dialog-blocks"
},
{
"include": "#dialog-choices"
},
{
"include": "#commands"
},
{
"include": "#variables"
},
{
"include": "#control-flow"
},
{
"include": "#strings"
},
{
"include": "#numbers"
},
{
"include": "#operators"
},
{
"include": "#keywords"
},
{
"include": "#builtin-variables"
},
{
"include": "#global-ids"
}
],
"repository": {
"comments": {
"patterns": [
{
"name": "comment.line.number-sign.ashes",
"begin": "#",
"end": "$",
"patterns": [
{
"name": "comment.line.number-sign.ashes",
"match": "."
}
]
}
]
},
"events": {
"patterns": [
{
"name": "entity.name.function.event.ashes",
"match": "^\\s*(:)([a-zA-Z_][a-zA-Z0-9_]*)(\\s*\\|\\s*[A-Z_]+)*",
"captures": {
"1": {
"name": "punctuation.definition.event.ashes"
},
"2": {
"name": "entity.name.function.event.ashes"
},
"3": {
"name": "entity.name.tag.event-flags.ashes"
}
}
},
{
"name": "entity.name.function.event-with-target.ashes",
"match": "^\\s*(:)([a-zA-Z_][a-zA-Z0-9_]*)(\\s*\\|\\s*[A-Z_]+)*\\s+(\"[^\"]*\")",
"captures": {
"1": {
"name": "punctuation.definition.event.ashes"
},
"2": {
"name": "entity.name.function.event.ashes"
},
"3": {
"name": "entity.name.tag.event-flags.ashes"
},
"4": {
"name": "string.quoted.double.event-target.ashes"
}
}
}
]
},
"dialog-blocks": {
"patterns": [
{
"name": "meta.dialog-block.ashes",
"begin": "^(\\s*)(\\?\\!)",
"beginCaptures": {
"1": {
"name": "punctuation.whitespace.indent.ashes"
},
"2": {
"name": "keyword.control.dialog.ashes"
}
},
"end": "^(?=\\1[^\\s]|\\s*$)",
"patterns": [
{
"include": "#dialog-choices"
},
{
"include": "#commands"
},
{
"include": "#variables"
},
{
"include": "#control-flow"
},
{
"include": "#strings"
},
{
"include": "#comments"
}
]
}
]
},
"dialog-choices": {
"patterns": [
{
"name": "meta.dialog-choice.ashes",
"begin": "^(\\s*)(-)\\s*(\"[^\"]*\")\\s*(\\[.*?\\])?",
"beginCaptures": {
"1": {
"name": "punctuation.whitespace.indent.ashes"
},
"2": {
"name": "punctuation.definition.dialog-choice.ashes"
},
"3": {
"name": "string.quoted.double.dialog-choice.ashes"
},
"4": {
"name": "meta.condition.dialog-choice.ashes"
}
},
"end": "^(?=\\1[^\\s-]|\\s*$)",
"patterns": [
{
"include": "#commands"
},
{
"include": "#variables"
},
{
"include": "#control-flow"
},
{
"include": "#strings"
},
{
"include": "#comments"
}
]
}
]
},
"commands": {
"patterns": [
{
"name": "support.function.command.ashes",
"match": "\\b(accept_input|anim|anim_block|block_say|camera_push|camera_push_block|camera_set_limits|camera_set_pos|camera_set_pos_block|camera_set_target|camera_set_target_block|camera_set_zoom|camera_set_zoom_block|camera_set_zoom_height|camera_set_zoom_height_block|camera_shift|camera_shift_block|change_scene|custom|dec_global|enable_terrain|end_block_say|hide_menu|inc_global|inventory_add|inventory_remove|item_count_add|play_lib_snd|play_snd|play_video|print|print_internal|queue_event|queue_resource|rand_global|repeat|save_game|say|say_last_dialog_option|say_random|say_sequence|sched_event|set_active|set_active_if_exists|set_angle|set_animations|set_direction|set_global|set_globals|set_gui_visible|set_interactive|set_item_custom_data|set_speed|set_state|set_tooltip|show_menu|slide|slide_block|spawn|stop|stop_snd|teleport|teleport_pos|transition|turn_to|wait|walk|walk_block|walk_to_pos|walk_to_pos_block)\\b",
"captures": {
"1": {
"name": "support.function.command.ashes"
}
}
},
{
"name": "meta.function-call.ashes",
"begin": "\\b([a-zA-Z_][a-zA-Z0-9_]*)\\s*(\\()",
"beginCaptures": {
"1": {
"name": "support.function.command.ashes"
},
"2": {
"name": "punctuation.definition.parameters.begin.ashes"
}
},
"end": "\\)",
"endCaptures": {
"0": {
"name": "punctuation.definition.parameters.end.ashes"
}
},
"patterns": [
{
"include": "#strings"
},
{
"include": "#numbers"
},
{
"include": "#global-ids"
},
{
"include": "#builtin-variables"
},
{
"include": "#operators"
}
]
}
]
},
"variables": {
"patterns": [
{
"name": "storage.type.variable.ashes",
"match": "\\b(var|global)\\b",
"captures": {
"1": {
"name": "storage.type.variable.ashes"
}
}
},
{
"name": "variable.other.ashes",
"match": "\\b([a-zA-Z_][a-zA-Z0-9_]*)\\s*(=)",
"captures": {
"1": {
"name": "variable.other.ashes"
},
"2": {
"name": "keyword.operator.assignment.ashes"
}
}
}
]
},
"control-flow": {
"patterns": [
{
"name": "keyword.control.ashes",
"match": "\\b(if|elif|else|while|break|done|stop|pass)\\b",
"captures": {
"1": {
"name": "keyword.control.ashes"
}
}
},
{
"name": "meta.control-flow.ashes",
"begin": "\\b(if|elif|while)\\s+",
"beginCaptures": {
"1": {
"name": "keyword.control.ashes"
}
},
"end": ":",
"endCaptures": {
"0": {
"name": "punctuation.separator.condition.ashes"
}
},
"patterns": [
{
"include": "#operators"
},
{
"include": "#builtin-variables"
},
{
"include": "#global-ids"
},
{
"include": "#strings"
},
{
"include": "#numbers"
}
]
}
]
},
"strings": {
"patterns": [
{
"name": "string.quoted.double.ashes",
"begin": "\"",
"end": "\"",
"patterns": [
{
"name": "constant.character.escape.ashes",
"match": "\\\\."
},
{
"name": "variable.other.global.ashes",
"match": "\\{[^}]+\\}"
}
]
},
{
"name": "string.quoted.single.ashes",
"begin": "'",
"end": "'",
"patterns": [
{
"name": "constant.character.escape.ashes",
"match": "\\\\."
}
]
}
]
},
"numbers": {
"patterns": [
{
"name": "constant.numeric.integer.ashes",
"match": "\\b\\d+\\b"
},
{
"name": "constant.numeric.float.ashes",
"match": "\\b\\d+\\.\\d+\\b"
}
]
},
"operators": {
"patterns": [
{
"name": "keyword.operator.arithmetic.ashes",
"match": "\\+|-|\\*|/"
},
{
"name": "keyword.operator.comparison.ashes",
"match": "==|!=|<=|>=|<|>"
},
{
"name": "keyword.operator.logical.ashes",
"match": "\\b(and|or|not)\\b|!"
},
{
"name": "keyword.operator.assignment.ashes",
"match": "="
}
]
},
"keywords": {
"patterns": [
{
"name": "constant.language.boolean.ashes",
"match": "\\b(true|false|nil)\\b"
},
{
"name": "keyword.other.ashes",
"match": "\\b(in|is|active)\\b"
}
]
},
"builtin-variables": {
"patterns": [
{
"name": "variable.language.builtin.ashes",
"match": "\\b(CURRENT_PLAYER|ESC_LAST_SCENE|ESC_CURRENT_SCENE|FORCE_LAST_SCENE_NULL|ANIMATION_RESOURCES)\\b"
}
]
},
"global-ids": {
"patterns": [
{
"name": "variable.other.global-id.ashes",
"match": "\\$([a-zA-Z_][a-zA-Z0-9_]*)",
"captures": {
"1": {
"name": "variable.other.global-id.ashes"
}
}
}
]
}
}
}

View File

@@ -0,0 +1,17 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "ES2020",
"outDir": "out",
"lib": [
"ES2020"
],
"sourceMap": true,
"rootDir": "src",
"strict": true
},
"exclude": [
"node_modules",
".vscode-test"
]
}

View File

@@ -0,0 +1 @@
/home/oier/.vscode-oss/extensions/vs-escoria4-ashes