Créer une extension pour vscode est assez simple mais pas très bien documenté. J’ai créé l’extension gimctl code generator afin de m’éviter des saisies fastidieuses. J’ai rencontré quelques difficultés et vais donc tenter de retracer ici les étapes de cette création pour mieux m’en suvenir et ne pas buter à nouveau dedans si l’idée me prend d’en développer d’autres.
Pré-requis
Pour développer un plugin pour VSCode il faut utiliser un package node.js qui s’appelle “VS code extension generator” (generator-code) un autre qui s’appalle “Yeoman” (yo) et un autre qui s’appelle “Visual Studio code Extensions” (@vscode/vsce), les deux premièrs serviront à créer le squelette de l’extension et le troisième à la packager. Tout est documenté sur le site de VSCode respectivement ici et là.
sudo npm install -g yo generator-code sudo npm install -g @vscode/vsce
Ce que je veux que mon extension fasse
Je veux me simplifier la vie pour écrire du code. Pour ce faire je veux créer une squelette de documentation au format markdown dans un répertoire, ainsi qu’un court fichier de description et mon fichier exécutable avec le strict minimum dedans.
De quoi ai-je besoin
- Du nom du script à créer
- D’une description de ce qu’il fait
- D’un répertoire de base sous lequel se trouve mon arborescence de scripts (pour pouvoir l’utiliser d’un contexte à un autre)
- De pouvoir interragir avec lespace de travail
Si les deux premiers doivent être saisis interractivement, le troisième peut être un paramètre de l’extension. Je veux donc pouvoir lire deux paramètres à chauque exécution de ma primitive et m’ppuyer sur un fichier de paramétrage propre à l’extension. Le quatrième c’est du code.
Génération du squelette
il suffit de taper “yo code” dans la ligne de commande, un script interractif demandera les informations nécessaires à la création du squelette. J’ai créé un squelette javascript. et donc eu un joly squelette de script qui fait hello world … dont je n’ai pas grand chose à carer. J’ai cependant obtenu deux fichiers intéressants:
- package.json
- extension.js
Modification(s) du ficier extension.js
Le premier décrit l’extension et son paramétrage et le second est le code proprement dit. Comme je le disais j’ai besoin d’interragir avec le workspace, autrement dit avec le système de fichier de VSCode. J’ai donc importé les deux bibliothèques “vscode” et “fs”, il est à noter que la première l’est déjà par le squeltte produit
const vscode = require('vscode'); const fs= require('fs');
ensuite j’ai modifié le nom de la commande créée
let disposable = vscode.commands.registerCommand('gimctl-code-generator.addGIMScript', () => { ... }
J’ai ensuite enchaînés deux dialogues pour récuprrer mes variables d’exécution:
vscode.window.showInputBox({ "placeHolder": 'Enter a for new script ' }).then((newScriptName) => { vscode.window.showInputBox({ "placeHolder": 'Enter a short description for script ' + newScriptName }).then((newScripDesc) => { ... }); });
Et enfin j’ai dû aller chercher le répertoire racine de mon workspace
const workspaceFolder = vscode.workspace.workspaceFolders ? vscode.workspace.workspaceFolders[0] : undefined;
Paramétrage global du module et prise en compte.
Je l’ai dit j’ai besoin d’un paramètre qui me dit ou trouver mon arborescence gimctl, ce paramètre change une fois pour toute pour chaque workspace, je n’ai donc pas besoin de le saisir à chaque fois que je crée un nouveau script (que j’utilise donc la primitive que j’écris). C’est donc un paramétrage d’extension. Je modifie le fichier package.json et plus particulièrement la sexion contributes afin de positionner toutes les bonnes informations pour mon plugin.
"contributes": { "commands": [{ "command": "gimctl-code-generator.addGIMScript", "title": "Add GIM script" }], "configuration": [{ "id": "cfgRootDir", "title": "Directory of gimctl in workspace", "properties": { "addGIMScript.gimctlRootDir": { "type":"string", "default": "gimctl" } } }] },
J’ai donc une section command qui décrit ma primitive et une section configuration qui décrit la variable workspace que je veux utiliser et qui par défaut vaudra gimctl. il faut maintenant que je me serve de ma variable globale dans mon code.
const gimctlRootDir = vscode.workspace.getConfiguration('addGIMScript').get('gimctlRootDir') ;
La primitive dans son ensemble
Au delà de récupérer des varaibles je veux créer des fichiers et écrire dedans. C’est assez simple et bien documenté, je laisse ici le code pour l’écriture de la varaible de description dans le fichier de description
const vscode = require('vscode'); const fs= require('fs'); function activate(context) { let disposable = vscode.commands.registerCommand('gimctl-code-generator.addGIMScript', () => { vscode.window.showInputBox({ "placeHolder": 'Enter a for new script ' }).then((newScriptName) => { vscode.window.showInputBox({ "placeHolder": 'Enter a short description for script ' + newScriptName }).then((newScripDesc) => { // Get the first workspace folder (if any) const workspaceFolder = vscode.workspace.workspaceFolders ? vscode.workspace.workspaceFolders[0] : undefined; const gimctlRootDir = vscode.workspace.getConfiguration('addGIMScript').get('gimctlRootDir') ; // Create a file in the specified subdirectory of the workspace const fileRootPath = workspaceFolder ? workspaceFolder.uri.fsPath + '/' + gimctlRootDir: undefined; if (!fileRootPath) { vscode.window.showErrorMessage('Error: No workspace folder opened'); return; } let filePath=fileRootPath + '/bin/' + newScriptName + '.sh'; if ( fs.existsSync(filePath) ) { vscode.window.showErrorMessage('Error: script ' + newScriptName + ' allready existing'); return; } let fileDescPath=fileRootPath + '/doc/' + newScriptName + '.desc'; let fileDocPath=fileRootPath + '/doc/' + newScriptName + '.md'; fs.writeFile(fileDescPath, newScripDesc, (err) => { if (err) { vscode.window.showErrorMessage('Error creating file: ' + err ); } else { vscode.window.showInformationMessage('File created successfully: ' + fileDescPath); } }); let mdDesc ='gimctl __' + newScriptName + '__' + MY_EOL ; ... fs.writeFile(fileDocPath, mdDesc, (err) => { if (err) { vscode.window.showErrorMessage('Error creating file: ' + err ); } else { vscode.window.showInformationMessage('File created successfully: ' + fileDocPath); } }); let shContent = '# ' + newScriptName + MY_EOL ; ... fs.writeFile(filePath, shContent, (err) => { if (err) { vscode.window.showErrorMessage('Error creating file: ' + err ); } else { vscode.window.showInformationMessage('File created successfully: ' + filePath); } }); }); }); }); context.subscriptions.push(disposable); } // This method is called when your extension is deactivated function deactivate() {} module.exports = { activate, deactivate }
C’est certes assez moche mais ça fait ce que je veux
Publier le package sur la marketplace
Préparer le package
Il faut avoir un compte sur le marcketplace et créer un “publisher” dedans. rien de compliqué ici.
Il faut ensuite modifier le fichier package.json afin de donner les informations souhaitée au marcketplace et de pouvoir publier notre extetension, c’est ici le début du fichier qui est modifié.
{ "name": "gimctl-code-generator", "displayName": "gimctl code generator", "publisher": "ojo-webdelphes", "description": "primitive de simplification d'écriture du code des scripts gimctl", "icon": "images/logo.png", "version": "0.0.3",
J’ai créé un fichier png logo.png que j’ai mis dans le répertoire images, pour que ma page de module ait un beau logo :), mais surtout j’ai préciser le publisher.
Il est aussi impossible de publier une option sans avoir mis à jour le fichier README.md, je l’ai donc fait. Le squelette guide, rien de compliqué, je ne détaille pas le contenu du fichier ici.
Crée le package
Un package vscode est un fichier .vsix il est créé par l’instruction vsce pckage lancée depuis le répertoire de travail.
ojoly%MAC-Pro gimctl-code-generator % vsce package WARNING A 'repository' field is missing from the 'package.json' manifest file. Do you want to continue? [y/N] y WARNING LICENSE.md, LICENSE.txt or LICENSE not found Do you want to continue? [y/N] y DONE Packaged: /Users/ojoly/devs/gimctl-code-generator/gimctl-code-generator-0.0.3.vsix (7 files, 9.46KB)
Il ne reste plus qu’à crée votre extension dans votre espace marcketplace et d’y télécharger le fichier .vsix généré (ici gimctl-code-generator-0.0.3.vsix) et après quelques minutes votre option peut être téléchargée depuis vscode et a sa page dans le marcketplace.
Installation et paramétrage
Chercher gimctl dans les extensions et cliquer sur installer | |
Cliquer sur l’icone de configuration, puis sur Paramètres d’extenion | |
Le paramètre rootdir peut être positionné soit pour le workspace courant soit pour l’utilisateur. | |
Ne reste qu’à utiliser CTRL+Shift+P pour appeler la primitive. Elle lancera successivement les dialogues souhaités et exécutera ce qui est demandé. |