Inhaltsverzeichnis

Control VSIX erstellen

Anleitung zur Erstellung einer VSIX Extension für ein WvdS Control.

Übersicht

Jedes WvdS Control wird als eigenständige VSIX Extension verteilt:

wvds-vscode-ui-{control}-0.1.0.vsix
├── package.json           # Extension Manifest
├── dist/
│   └── extension_main.js  # Kompilierter Code
├── images/
│   └── icon.png           # Extension Icon
└── pas/
    └── extension_main.pas # Pascal-Quellcode

Verzeichnisstruktur

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

Schritt 1: Verzeichnis erstellen

$ControlName = "mycontrol"
$Category = "editors"
$BasePath = "sources/extensions/wvds.vscode.ui.controls"
 
New-Item -ItemType Directory -Path "$BasePath/$Category/wvds.vscode.ui.$ControlName/pas" -Force

Schritt 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"
}

Schritt 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 = '<MyControl Name="myControl1" />';
    vscode.window.activeTextEditor?.insertSnippet(
      new vscode.SnippetString(snippet)
    );
  end;
end;
 
exports
  Activate,
  Deactivate;
 
begin
end.

Schritt 4: build.cfg

-Mobjfpc
-Tnodejs
-O-
-Jc
-Jirtl.js
-Fu../../../common
-FUpas
-FEdist
-odist/extension_main.js

Schritt 5: Kompilieren

$ExtPath = "sources/extensions/wvds.vscode.ui.controls/editors/wvds.vscode.ui.mycontrol"
 
# Kompilieren mit pas2js
pas2js @"$ExtPath/build.cfg" "$ExtPath/pas/extension_main.pas"

Schritt 6: VSIX packen

cd $ExtPath
 
# Icon kopieren (falls nicht vorhanden)
if (-not (Test-Path "images")) {
    New-Item -ItemType Directory -Path "images" -Force
    Copy-Item "%MEDIA%/wvds_fpc.png" "images/icon.png"
}
 
# VSIX erstellen
vsce package --no-dependencies
 
# Nach dist verschieben
Move-Item "*.vsix" "%BINARIES%/dist/"

Snippet-Definition

Erstelle snippets/mycontrol.json:

{
  "WvdS MyControl": {
    "prefix": "wvds-mycontrol",
    "body": [
      "<MyControl",
      "    Name=\"${1:myControl1}\"",
      "    ${2:Property}=\"${3:Value}\"",
      "/>"
    ],
    "description": "Insert WvdS MyControl"
  }
}

Vollständiges Beispiel

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(
            '<Button\n' +
            '    Name="${1:button1}"\n' +
            '    Caption="${2:Click Me}"\n' +
            '    OnClick="${3:OnButtonClick}"\n' +
            '/>'
          );
          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(
            '<Button Name="${1:button1}" Caption="${2:Click Me}" />'
          );
          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-Generierung

Für mehrere Controls, siehe Control-Generierung.

Troubleshooting

pas2js Fehler

Fehler Lösung
class var nicht unterstützt Unit-Level Variable verwenden
Int64 nicht unterstützt Integer verwenden