Creating our own Visual Studio Code extensions. Making promises come true
Views (406)
Extension, a word with too many meanings
When we began to study VSCODE AL extensions, we had three different definitions for “extension” word: file extensions (.al, .json, etc.), AL extensions for Business Central final user, and extensions for VSCODE developers:
The last meaning (extensions for VSCODE developers) is we are going to talk about: you miss a feature in Visual Studio Code editor, and you make the decision to develop this feature by yourself.
Tools and skills to build our own extensions
What do we need to add a new feature to Visual Studio? The tools are VSCODE itself, Node and Yeoman. We will talk about that later. Now let´s see the skills you need to develop a new extension:
JavaScript: We must program a new VSCODE extension with JavaScript or TypeScript (typed JavaScript). So, you have to learn JavaScript but, how much JavaScript do you need to learn? That´s a good question. On one hand we have the obvious “the more the better”, but on the other we have lot of JavaScript support in the web, snippets, lint tools for dev people, so you may not need so much knowledge. Anyway, I think there are many reasons for an AL developer to learn JavaScript, making new extensions aside.
Visual Studio Code API: You need to handle Visual Studio internal objects and features, and VSCODE API gives you this access. Learning VSC API is the hardest part of the deal (in my opinion), because it is a very huge and complex object set. To help us in this hard pre-requisite you have useful resources in the API description link: https://code.visualstudio.com/api/references/vscode-api . We have a good first sight in https://code.visualstudio.com/api/extension-capabilities/common-capabilities and this repo with examples: https://github.com/microsoft/vscode-extension-samples
Tools and start
We need these tools to start: Node, Yeoman and the obvious need, VSCODE. Yeoman is not mandatory but very useful, because without any knowledge about Node applications, makes all the scaffold of setup files and dependencies to start a new extension. Make no sense to explain in an exhaustive way how to begin an extension, because here we are this post: https://code.visualstudio.com/api/get-started/your-first-extension is simple, is easy and works. In a few words: step one install Node, step two install Yeoman and step three exec in npm “Yo code” command and follow the assistant. At the end of the process we have an example extension project. If we want to start developing a new extension form this example, you must focus in two project files: package.json and extension.js.
A very important JavaScript pattern for VSCODE extensions develop: promises
In the book “Visual Studio Code”, author Bruce Johnson, highlights three JS patterns involved in extensions developing: Promises, Events and Cancelation Tokens.
Since the first steps with VSCODE API, my main fight was with promises. If you have a look to VSCODE API, most of its methods return an object with the prefix “Thenable”.
What does “Thenable” term mean?: the method returns a value, but in an async way. About create a show open file dialog asynchronous we saw above: Do you think it make sense? No, in my opinion, but you will find that almost all methods in this API return a promise.
Let´s do an example to understand promises in with Visual Studio Code API: We want to create a new extension with a command (the actions we trigger with F1 in VSCODE editor) that shows an open file dialog and display the selected file name in the status bar. For this purpose, we can overwrite the “Hello world” code generated in the previous block and write this code instead:
let disposable = vscode.commands.registerCommand('Promises.BadPromise', function () {
BadShowFileNameInStatus()
});
function BadShowFileNameInStatus()
{
console.log(BadReturn());
}
function BadReturn()
{
vscode.window.showOpenDialog(options).then(fileUri => {
return(fileUri[0].fsPath);
});
}
We must change in Package.json the name of the command this way:
"activationEvents": [
"onCommand:Promises.BadPromise",
],
"main": "./extension.js",
"contributes": {
"commands": [
{
"command": "Promises.BadPromise",
Then we can run the application push F5 as you do in AL, and find the command “Promise: not in time”:
When console log is executed:
console.log(BadReturn());
the log shows “undefined”. This happens because we try to log the return value before the promise is resolved.
We can fix this behavior it is putting the code after “then” statement this way:
vscode.window.showOpenDialog(options).then(fileUri => {
vscode.window.setStatusBarMessage(fileUri[0].fsPath);
Then we can see it works and finally the selected file name is displayed in the status bar:
Waiting for the promise.
It is very important to know how to work with promises. But sometimes we don´t want to manage promises: in the “open dialog” example could be more useful waiting for the response, and implement the actions outside the “then” statement. This way too, we avoid to write a lot of nested promises getting a cleaner code. If you want to use the selected filename to open it and process it, could be more effective convert async execution into sync execution this way:
async function GoodShowFileNameInStatus()
{
let FileName = await GoodReturn();
vscode.window.setStatusBarMessage(FileName);
}
async function GoodReturn()
{
let fileUri = await vscode.window.showOpenDialog(options);
return(fileUri[0].fsPath);
}
We use “async” statement before the function and “await” for the response declaration “let” statement. This way execution is stopped until we get the file name. In my opinion in this occasion is better to stop the execution until we get the data, than nest a chain of “then” to perform these kinds of actions.
All the code in repo: https://github.com/JalmarazMartn/Promises
Comments
-
A hard way. This post keep diving in Visual Studio API, as this other post did: Creating our own Visual Studio Code extensions. Making promises come true - Dynamics 365 Business Centra...

Like
Report
*This post is locked for comments