LavishScript by user01
Comprehensive LavishScript language support for Visual Studio Code.
Support Development
If you find this extension helpful, consider supporting its continued development:
Bitcoin (BTC): 1HUixTpx719Jeo5ruEeZkhHDcddKybYK2Y
Ethereum (ETH): 0x01B54939a97F235cB050ce105214D6c098D37BcE
Your donations help maintain and improve this extension for the LavishScript community.
Features
- Syntax Highlighting: Full syntax highlighting for
.iss, .lib, and .inc files
- Code Completion: Intelligent autocomplete for keywords, variables, functions, methods, and members
- Go to Definition: Navigate to symbol definitions with Ctrl+Click
- Hover Information: View type and documentation on hover
- Document Outline: Navigate code structure via breadcrumbs and outline view
- Include Tree: Visual tree view of file include hierarchy
- Diagnostics: Real-time error detection for:
- Duplicate variable declarations
- Unknown function/type references
- Invalid comment syntax
- Style issues
LavishScript Syntax Quick Reference
; Single line comment
/* Multi-line
comment */
Variables
variable string myString
variable(global) int myInt
declare myVar string local "default"
Functions & Methods
function MyFunction(string param1, int param2)
{
return
}
objectdef MyClass
{
method Initialize()
{
}
member:string Name
{
return "MyClass"
}
atom OnEvent()
{
}
}
Include Files
#include "path/to/file.iss"
#include "${LavishScript.HomeDirectory}/Scripts/utility.lib"
Creating Companion Extensions
This extension exposes an API that allows companion extensions to register additional TLOs, datatypes, and commands. This is useful for game-specific or application-specific APIs that extend the base LavishScript functionality.
Overview
Companion extensions can register:
- TLOs (Top-Level Objects) - Global accessor objects like
Player, World, Config
- Datatypes - Custom types with members and methods
- Commands - Script commands
Once registered, these will:
- Appear in autocomplete suggestions
- Show hover documentation
- Not trigger "unknown reference" diagnostics
- Support member/method chaining
Quick Start
1. Create Extension Structure
my-api-extension/
├── package.json
├── extension.js
└── api-definitions.yml (optional)
2. package.json
{
"name": "my-custom-api",
"displayName": "My Custom API for LavishScript",
"version": "1.0.0",
"engines": {
"vscode": "^1.74.0"
},
"activationEvents": [
"onLanguage:iss",
"onLanguage:lib",
"onLanguage:inc"
],
"extensionDependencies": [
"user01x.lavishscript-by-user01"
],
"main": "./extension.js"
}
Key points:
extensionDependencies ensures the base extension loads first
- Activation events match LavishScript file types
3. extension.js - Basic Example
const vscode = require('vscode');
async function activate(context) {
// Get the LavishScript extension
const lavishExt = vscode.extensions.getExtension('user01x.lavishscript-by-user01');
if (!lavishExt) {
console.warn('LavishScript extension not found');
return;
}
// Wait for it to activate and get the API
const api = await lavishExt.activate();
// Register your data
api.registerParserData({
commands: ['mycommand', 'processdata', 'initialize'],
tlos: [
{ name: 'Config', returns: 'configdata', description: 'Application configuration' },
{ name: 'Session', returns: 'sessioninfo', description: 'Current session information' }
],
objectTypes: {
'configdata': {
name: 'configdata',
members: [
{ name: 'Name', type: 'string', description: 'Configuration name' },
{ name: 'Version', type: 'int', description: 'Configuration version' },
{ name: 'IsValid', type: 'bool', description: 'Whether config is valid' }
],
methods: [
{ name: 'Reload', returns: 'bool', description: 'Reload configuration' },
{ name: 'Save', returns: 'bool', description: 'Save current configuration' }
]
},
'sessioninfo': {
name: 'sessioninfo',
members: [
{ name: 'ID', type: 'string', description: 'Session identifier' },
{ name: 'StartTime', type: 'time', description: 'When session started' },
{ name: 'IsActive', type: 'bool', description: 'Whether session is active' }
],
methods: [
{ name: 'Terminate', returns: 'bool', description: 'End the session' }
]
}
}
});
console.log('My API extension registered with LavishScript');
}
function deactivate() {}
module.exports = { activate, deactivate };
API Reference
api.registerParserData(data)
Register all data in one call (recommended approach).
api.registerParserData({
commands: string[], // Array of command names
tlos: TLO[], // Array of TLO definitions
objectTypes: { [name]: Type } // Map of datatype definitions
});
api.addKnownCommands(commands)
Register just command names.
api.addKnownCommands(['start', 'stop', 'reset', 'configure']);
api.addKnownTLOs(tlos)
Register just TLO names (simple strings, no metadata).
api.addKnownTLOs(['Config', 'Session', 'Application']);
api.addObjectTypes(types)
Register datatypes with full member/method definitions.
api.addObjectTypes({
'mytype': {
name: 'mytype',
members: [...],
methods: [...]
}
});
api.registerAdditionalParser(name, parser)
Register a parser object with getter methods. Useful for dynamically generated definitions.
api.registerAdditionalParser('MyAPI', {
getTLONames() {
return ['Config', 'Session'];
},
getTLO(name) {
return { name, returns: 'mytype', description: '...' };
},
getCommands() {
return ['start', 'stop'];
},
getAllDataTypes() {
return { 'mytype': {...} };
}
});
Data Structures
TLO Definition
{
name: 'Config', // TLO name (case-sensitive for display)
returns: 'configdata', // Return type (datatype name)
description: 'Application configuration',
wikiUrl: 'https://...', // Optional: documentation link
parameters: [ // Optional: for indexed TLOs
{ type: 'string', name: 'section', optional: true }
]
}
Datatype Definition
{
name: 'configdata',
description: 'Configuration data container',
inherits: 'baseobject', // Optional: parent type
wikiUrl: 'https://...',
members: [
{
name: 'Name',
type: 'string',
description: 'Configuration name',
parameters: []
},
{
name: 'Setting',
type: 'string',
description: 'Get setting by key',
parameters: [
{ type: 'string', name: 'key', optional: false }
]
}
],
methods: [
{
name: 'Save',
returns: 'bool',
description: 'Save configuration to disk',
parameters: [
{ type: 'string', name: 'filename', optional: true }
]
}
]
}
Complete Example with YAML Loading
const vscode = require('vscode');
const yaml = require('js-yaml');
const fs = require('fs');
const path = require('path');
async function activate(context) {
const lavishExt = vscode.extensions.getExtension('user01x.lavishscript-by-user01');
if (!lavishExt) return;
const api = await lavishExt.activate();
// Load from YAML file
const yamlPath = path.join(context.extensionPath, 'my_api.yml');
const yamlContent = fs.readFileSync(yamlPath, 'utf8');
const apiDef = yaml.load(yamlContent);
// Register TLOs
const tlos = [];
for (const [name, tlo] of Object.entries(apiDef.tlos || {})) {
tlos.push({
name: tlo.name || name,
returns: tlo.returns || name.toLowerCase(),
description: tlo.description || '',
wikiUrl: tlo.wikiUrl || '',
parameters: tlo.parameters || []
});
}
// Register datatypes
const objectTypes = {};
for (const [name, dtype] of Object.entries(apiDef.datatypes || {})) {
objectTypes[name.toLowerCase()] = {
name: dtype.name || name,
description: dtype.description || '',
inherits: dtype.inherits || '',
wikiUrl: dtype.wikiUrl || '',
members: (dtype.members || []).map(m => ({
name: m.name,
type: m.type || 'string',
description: m.description || '',
parameters: m.parameters || []
})),
methods: (dtype.methods || []).map(m => ({
name: m.name,
returns: m.returns || 'void',
description: m.description || '',
parameters: m.parameters || []
}))
};
}
// Register commands
const commands = Object.keys(apiDef.commands || {});
// Register everything
api.registerParserData({ commands, tlos, objectTypes });
console.log(`Registered ${tlos.length} TLOs, ${Object.keys(objectTypes).length} types, ${commands.length} commands`);
}
function deactivate() {}
module.exports = { activate, deactivate };
Example my_api.yml:
version: 1.0.0
tlos:
Config:
name: Config
description: Application configuration accessor
returns: configdata
Session:
name: Session
description: Current session information
returns: sessioninfo
DataStore:
name: DataStore
description: Access stored data by key
returns: storeddata
parameters:
- type: string
name: key
optional: true
datatypes:
configdata:
name: configdata
description: Configuration data container
members:
- name: Name
type: string
description: Configuration name
- name: Version
type: int
description: Version number
- name: LastModified
type: time
description: Last modification time
- name: IsReadOnly
type: bool
description: Whether config is read-only
methods:
- name: Reload
returns: bool
description: Reload from disk
- name: Save
returns: bool
description: Save to disk
parameters:
- type: string
name: filename
optional: true
sessioninfo:
name: sessioninfo
description: Session information
members:
- name: ID
type: string
description: Unique session identifier
- name: StartTime
type: time
description: Session start time
- name: Duration
type: int
description: Session duration in seconds
- name: IsActive
type: bool
description: Whether session is active
methods:
- name: Terminate
returns: bool
description: End the session
storeddata:
name: storeddata
description: Stored data container
members:
- name: Key
type: string
description: Data key
- name: Value
type: string
description: Data value
- name: Timestamp
type: time
description: When data was stored
methods:
- name: Update
returns: bool
description: Update the stored value
parameters:
- type: string
name: newValue
optional: false
- name: Delete
returns: bool
description: Delete this entry
commands:
initialize:
name: initialize
description: Initialize the application
shutdown:
name: shutdown
description: Gracefully shut down
reload:
name: reload
description: Reload all configurations
Debug API
The LavishScript extension provides debug utilities:
const api = await lavishExt.activate();
// Refresh diagnostics after registration
api.debug.refreshDiagnostics();
// Inspect registered data
console.log('TLOs:', api.debug.getAdditionalTLOs());
console.log('Commands:', api.debug.getAdditionalCommands());
console.log('Types:', api.debug.getAdditionalObjectTypes());
Best Practices
- Use
extensionDependencies - Ensures proper load order
- Handle missing base extension - Check if
lavishExt exists before using
- Use YAML for large APIs - Easier to maintain than inline JS objects
- Include
wikiUrl - Enables documentation linking
- Match return types - TLO
returns should match a registered datatype name
- Use lowercase for type lookups - The system normalizes to lowercase internally
Troubleshooting
Extension not loading:
- Check
extensionDependencies in package.json
- Verify extension ID:
user01x.lavishscript-by-user01
TLOs/types not appearing in autocomplete:
- Ensure datatypes are registered before TLOs reference them
- Check console for registration errors
Still seeing "unknown" warnings:
- Call
api.debug.refreshDiagnostics() after registration
- Verify names match exactly (case-insensitive for lookups)