====== Creating Control VSIX ======
Guide to creating a VSIX Extension for a WvdS Control.
===== Overview =====
Each WvdS Control is distributed as a standalone VSIX Extension:
wvds-vscode-ui-{control}-0.1.0.vsix
├── package.json # Extension Manifest
├── dist/
│ └── extension_main.js # Compiled Code
├── images/
│ └── icon.png # Extension Icon
└── pas/
└── extension_main.pas # Pascal source code
===== Directory Structure =====
sources/extensions/wvds.vscode.ui.controls/
├── {category}/
│ └── wvds.vscode.ui.{control}/
│ ├── package.json
│ ├── build.cfg
│ ├── pas/
│ │ └── extension_main.pas
│ └── dist/ # Build output
│ └── extension_main.js
===== Step 1: Create Directory =====
$ControlName = "mycontrol"
$Category = "editors"
$BasePath = "sources/extensions/wvds.vscode.ui.controls"
New-Item -ItemType Directory -Path "$BasePath/$Category/wvds.vscode.ui.$ControlName/pas" -Force
===== Step 2: package.json =====
{
"name": "wvds-vscode-ui-mycontrol",
"displayName": "WvdS UI: MyControl",
"description": "MyControl component for WvdS UI Framework",
"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": {
"snippets": [
{
"language": "pxaml",
"path": "./snippets/mycontrol.json"
}
]
},
"repository": {
"type": "git",
"url": "https://github.com/ArmandoFilho/WvdS.FPC"
},
"license": "MIT"
}
===== Step 3: extension_main.pas =====
library extension_main;
{$mode objfpc}
{$modeswitch externalclass}
uses
JS, Web,
VSCode.Base, VSCode.Commands, VSCode.Window;
type
TExtension = class
public
class procedure Activate(AContext: TVSCodeExtensionContext);
class procedure Deactivate;
end;
class procedure TExtension.Activate(AContext: TVSCodeExtensionContext);
var
Disposable: TVSCodeDisposable;
begin
(* Register snippet provider *)
Disposable := TVSCodeCommands.RegisterCommand(
'wvds.ui.mycontrol.insert',
@InsertSnippet
);
AContext.Subscriptions.Push(Disposable);
end;
class procedure TExtension.Deactivate;
begin
(* Cleanup *)
end;
procedure InsertSnippet;
begin
asm
const snippet = '';
vscode.window.activeTextEditor?.insertSnippet(
new vscode.SnippetString(snippet)
);
end;
end;
exports
Activate,
Deactivate;
begin
end.
===== Step 4: build.cfg =====
-Mobjfpc
-Tnodejs
-O-
-Jc
-Jirtl.js
-Fu../../../common
-FUpas
-FEdist
-odist/extension_main.js
===== Step 5: Compile =====
$ExtPath = "sources/extensions/wvds.vscode.ui.controls/editors/wvds.vscode.ui.mycontrol"
# Compile with pas2js
pas2js @"$ExtPath/build.cfg" "$ExtPath/pas/extension_main.pas"
===== Step 6: Package VSIX =====
cd $ExtPath
# Copy icon (if not present)
if (-not (Test-Path "images")) {
New-Item -ItemType Directory -Path "images" -Force
Copy-Item "%MEDIA%/wvds_fpc.png" "images/icon.png"
}
# Create VSIX
vsce package --no-dependencies
# Move to dist
Move-Item "*.vsix" "%BINARIES%/dist/"
===== Snippet Definition =====
Create ''snippets/mycontrol.json'':
{
"WvdS MyControl": {
"prefix": "wvds-mycontrol",
"body": [
""
],
"description": "Insert WvdS MyControl"
}
}
===== Complete Example =====
==== Button Extension ====
library extension_main;
{$mode objfpc}
{$modeswitch externalclass}
uses
JS, Web,
VSCode.Base, VSCode.Commands, VSCode.Window,
VSCode.Languages, VSCode.CompletionItem;
const
CONTROL_NAME = 'Button';
CONTROL_CATEGORY = 'Basic Controls';
CONTROL_ICON = 'symbol-event';
type
TButtonExtension = class
public
class procedure Activate(AContext: TVSCodeExtensionContext);
class procedure Deactivate;
private
class procedure RegisterSnippet(AContext: TVSCodeExtensionContext);
class procedure RegisterCompletionProvider(AContext: TVSCodeExtensionContext);
end;
class procedure TButtonExtension.Activate(AContext: TVSCodeExtensionContext);
begin
RegisterSnippet(AContext);
RegisterCompletionProvider(AContext);
asm
console.log('WvdS UI: Button extension activated');
end;
end;
class procedure TButtonExtension.Deactivate;
begin
(* Cleanup *)
end;
class procedure TButtonExtension.RegisterSnippet(AContext: TVSCodeExtensionContext);
var
Cmd: TVSCodeDisposable;
begin
Cmd := TVSCodeCommands.RegisterCommand(
'wvds.ui.button.insert',
procedure
begin
asm
const editor = vscode.window.activeTextEditor;
if (editor) {
const snippet = new vscode.SnippetString(
''
);
editor.insertSnippet(snippet);
}
end;
end
);
AContext.Subscriptions.Push(Cmd);
end;
class procedure TButtonExtension.RegisterCompletionProvider(
AContext: TVSCodeExtensionContext);
begin
(* PXAML completion provider *)
asm
const provider = vscode.languages.registerCompletionItemProvider(
{ language: 'pxaml', scheme: 'file' },
{
provideCompletionItems(document, position) {
const item = new vscode.CompletionItem('Button', vscode.CompletionItemKind.Class);
item.insertText = new vscode.SnippetString(
''
);
item.documentation = 'WvdS Button control';
return [item];
}
},
'<'
);
AContext.subscriptions.push(provider);
end;
end;
procedure Activate(AContext: TJSObject);
begin
TButtonExtension.Activate(TVSCodeExtensionContext(AContext));
end;
procedure Deactivate;
begin
TButtonExtension.Deactivate;
end;
exports
Activate,
Deactivate;
begin
end.
===== Batch Generation =====
For multiple controls, see [[.:control-generierung|Control Generation]].
===== Troubleshooting =====
==== pas2js Errors ====
| Error | Solution |
^ ''class var'' not supported | Use Unit-Level Variable |
^ ''Int64'' not supported | Use ''Integer'' |
^ ''//'' in asm block | Use ''/* */'' for JS comments |
==== VSIX Errors ====
| Error | Solution |
^ Missing publisher | Set ''publisher'' in package.json |
^ Icon not found | Create ''images/icon.png'' |
^ Invalid main | Check path in ''main'' |
===== See Also =====
* [[.:control-generierung|Control Generation]]
* [[.:control-architektur|Control Architecture]]
* [[.:extension-entwicklung|Extension Development]]