====== Control Generation ======
Automated generation of Control VSIX Extensions.
===== Overview =====
The WvdS Control Library uses PowerShell scripts for batch generation:
| Script | Purpose |
^ create-new-controls.ps1 | Create directory structure |
^ regenerate-pas.ps1 | Generate Pascal source code |
^ fix-package-json.ps1 | Generate package.json files |
^ package-all.ps1 | Compile and package all VSIX |
===== Directory Structure =====
sources/extensions/wvds.vscode.ui.controls/
├── control-definitions.json # Control metadata
├── create-new-controls.ps1
├── regenerate-pas.ps1
├── fix-package-json.ps1
├── package-all.ps1
│
├── basic/
│ ├── wvds.vscode.ui.button/
│ ├── wvds.vscode.ui.label/
│ └── ...
├── editors/
├── navigation/
├── data/
├── charts/
├── gauges/
├── layout/
├── bars/
└── specialized/
===== control-definitions.json =====
{
"controls": [
{
"name": "Button",
"category": "basic",
"displayName": "Button",
"description": "Standard button control",
"icon": "symbol-event",
"snippet": ""
},
{
"name": "TextEdit",
"category": "editors",
"displayName": "Text Edit",
"description": "Single-line text input",
"icon": "symbol-string",
"snippet": ""
}
// ... more controls
]
}
===== create-new-controls.ps1 =====
Creates directory structure for new controls:
# create-new-controls.ps1
param(
[string]$DefinitionsFile = "control-definitions.json"
)
$Definitions = Get-Content $DefinitionsFile | ConvertFrom-Json
foreach ($Control in $Definitions.controls) {
$ControlLower = $Control.name.ToLower()
$Category = $Control.category
$Path = "$Category/wvds.vscode.ui.$ControlLower"
if (-not (Test-Path $Path)) {
Write-Host "Creating: $Path"
New-Item -ItemType Directory -Path "$Path/pas" -Force | Out-Null
New-Item -ItemType Directory -Path "$Path/dist" -Force | Out-Null
New-Item -ItemType Directory -Path "$Path/images" -Force | Out-Null
}
}
Write-Host "Done. Created directories for $($Definitions.controls.Count) controls."
===== regenerate-pas.ps1 =====
Generates Pascal source code from template:
# regenerate-pas.ps1
param(
[string]$DefinitionsFile = "control-definitions.json",
[switch]$Force
)
$Template = @'
library extension_main;
{$mode objfpc}
{$modeswitch externalclass}
uses
JS, Web,
VSCode.Base, VSCode.Commands, VSCode.Window;
const
CONTROL_NAME = '{{NAME}}';
CONTROL_DISPLAY = '{{DISPLAY}}';
CONTROL_CATEGORY = '{{CATEGORY}}';
procedure InsertSnippet;
begin
asm
const editor = vscode.window.activeTextEditor;
if (editor) {
const snippet = new vscode.SnippetString('{{SNIPPET}}');
editor.insertSnippet(snippet);
}
end;
end;
procedure Activate(AContext: TJSObject);
var
Cmd: TJSObject;
begin
asm
Cmd = vscode.commands.registerCommand(
'wvds.ui.{{NAME_LOWER}}.insert',
InsertSnippet
);
AContext.subscriptions.push(Cmd);
console.log('WvdS UI: {{DISPLAY}} extension activated');
end;
end;
procedure Deactivate;
begin
end;
exports
Activate,
Deactivate;
begin
end.
'@
$Definitions = Get-Content $DefinitionsFile | ConvertFrom-Json
foreach ($Control in $Definitions.controls) {
$ControlLower = $Control.name.ToLower()
$Category = $Control.category
$PasFile = "$Category/wvds.vscode.ui.$ControlLower/pas/extension_main.pas"
if ($Force -or -not (Test-Path $PasFile)) {
$Code = $Template `
-replace '{{NAME}}', $Control.name `
-replace '{{NAME_LOWER}}', $ControlLower `
-replace '{{DISPLAY}}', $Control.displayName `
-replace '{{CATEGORY}}', $Control.category `
-replace '{{SNIPPET}}', ($Control.snippet -replace '"', '\"')
$Code | Out-File -FilePath $PasFile -Encoding UTF8NoBOM
Write-Host "Generated: $PasFile"
}
}
===== fix-package-json.ps1 =====
Generates package.json for all controls:
# fix-package-json.ps1
param(
[string]$DefinitionsFile = "control-definitions.json"
)
$Definitions = Get-Content $DefinitionsFile | ConvertFrom-Json
foreach ($Control in $Definitions.controls) {
$ControlLower = $Control.name.ToLower()
$Category = $Control.category
$PackageFile = "$Category/wvds.vscode.ui.$ControlLower/package.json"
$Package = @{
name = "wvds-vscode-ui-$ControlLower"
displayName = "WvdS UI: $($Control.displayName)"
description = $Control.description
version = "0.1.0"
publisher = "ArmandoFilho"
icon = "images/icon.png"
engines = @{ vscode = "^1.85.0" }
categories = @("Other")
activationEvents = @("onLanguage:pxaml")
main = "./dist/extension_main.js"
contributes = @{
commands = @(
@{
command = "wvds.ui.$ControlLower.insert"
title = "Insert $($Control.displayName)"
category = "WvdS UI"
}
)
}
repository = @{
type = "git"
url = "https://github.com/ArmandoFilho/WvdS.FPC"
}
license = "MIT"
}
$Package | ConvertTo-Json -Depth 10 | Out-File -FilePath $PackageFile -Encoding UTF8NoBOM
Write-Host "Generated: $PackageFile"
}
===== package-all.ps1 =====
Compiles and packages all VSIX Extensions:
# package-all.ps1
param(
[switch]$Force,
[string]$OutputDir = "%BINARIES%/dist"
)
$Categories = @("basic", "editors", "navigation", "data", "charts", "gauges", "layout", "bars", "specialized")
$Success = 0
$Failed = 0
foreach ($Category in $Categories) {
$Extensions = Get-ChildItem -Path $Category -Directory -ErrorAction SilentlyContinue
foreach ($Ext in $Extensions) {
$ExtPath = $Ext.FullName
$PasFile = "$ExtPath/pas/extension_main.pas"
$JsFile = "$ExtPath/dist/extension_main.js"
Write-Host "`n=== Building: $($Ext.Name) ==="
# 1. Compile
if ($Force -or -not (Test-Path $JsFile)) {
$BuildCfg = "$ExtPath/build.cfg"
if (-not (Test-Path $BuildCfg)) {
# Create simple build.cfg
@"
-Mobjfpc
-Tnodejs
-O-
-FEdist
-odist/extension_main.js
"@ | Out-File -FilePath $BuildCfg -Encoding UTF8NoBOM
}
& pas2js "@$BuildCfg" $PasFile
if ($LASTEXITCODE -ne 0) {
Write-Host "FAILED: Compilation error" -ForegroundColor Red
$Failed++
continue
}
}
# 2. Copy icon
$IconPath = "$ExtPath/images/icon.png"
if (-not (Test-Path $IconPath)) {
New-Item -ItemType Directory -Path "$ExtPath/images" -Force | Out-Null
Copy-Item "%MEDIA%/wvds_fpc.png" $IconPath
}
# 3. Package VSIX
Push-Location $ExtPath
& vsce package --no-dependencies 2>&1 | Out-Null
$VsixFile = Get-ChildItem -Filter "*.vsix" | Select-Object -First 1
if ($VsixFile) {
Move-Item $VsixFile.FullName "$OutputDir/" -Force
Write-Host "SUCCESS: $($VsixFile.Name)" -ForegroundColor Green
$Success++
} else {
Write-Host "FAILED: VSIX not created" -ForegroundColor Red
$Failed++
}
Pop-Location
}
}
Write-Host "`n=== Summary ==="
Write-Host "Success: $Success"
Write-Host "Failed: $Failed"
Write-Host "Total: $($Success + $Failed)"
===== Workflow =====
==== Adding New Controls ====
# 1. Extend definitions
# Edit control-definitions.json
# 2. Create directories
.\create-new-controls.ps1
# 3. Generate Pascal code
.\regenerate-pas.ps1 -Force
# 4. Generate package.json
.\fix-package-json.ps1
# 5. Build all
.\package-all.ps1 -Force
==== Updating a Single Control ====
$Control = "button"
$Category = "basic"
$Path = "$Category/wvds.vscode.ui.$Control"
# Compile
pas2js -Mobjfpc -Tnodejs -O- -FEdist -odist/extension_main.js "$Path/pas/extension_main.pas"
# Package
Push-Location $Path
vsce package --no-dependencies
Move-Item *.vsix "%BINARIES%/dist/"
Pop-Location
===== Result =====
After successful generation:
binaries/dist/
├── wvds-vscode-ui-button-0.1.0.vsix
├── wvds-vscode-ui-label-0.1.0.vsix
├── wvds-vscode-ui-textedit-0.1.0.vsix
├── ... (108 VSIX packages)
└── wvds-vscode-ui-zoomtrackbar-0.1.0.vsix
Total: ~7.2 MB (108 packages at ~67 KB each)
===== Installation =====
# Install single control
code --install-extension "%BINARIES%/dist/wvds-vscode-ui-button-0.1.0.vsix"
# Install all controls
Get-ChildItem "%BINARIES%/dist/wvds-vscode-ui-*.vsix" | ForEach-Object {
code --install-extension $_.FullName
}
===== See Also =====
* [[.:control-vsix-erstellen|Create VSIX (Manual)]]
* [[.:control-bibliothek|Control Library]]
* [[.:build-pipeline|Build Pipeline]]