Skip to content

API

It is possible to write VS Code extensions that are based on Code for IBM i. That means your extension can use the connection that the user creates in your extension. This is not an extension tutorial, but an intro on how to access the APIs available within Code for IBM i.

For example, you might be a vendor that produces lists or HTML that you’d like to be accessible from within Visual Studio Code.

Exports

As well as the basic VS Code command API, you can get access to the Code for IBM i API with the VS Code getExtension API.

const { instance } = vscode.extensions.getExtension(`halcyontechltd.code-for-ibmi`).exports;

Typings

We provide TS type definitions to make using the Code for IBM i API easier. They can be installed via npm:

terminal
npm i @halcyontech/vscode-ibmi-types

It can then be imported and used in combination with getExtension:

import type { CodeForIBMi } from '@halcyontech/vscode-ibmi-types';
//...
const ext = vscode.extensions.getExtension<CodeForIBMi>('halcyontechltd.code-for-ibmi');

Example import

This example can be used as a simple way to access the Code for IBM i instance.

import { CodeForIBMi } from "@halcyontech/vscode-ibmi-types";
import Instance from "@halcyontech/vscode-ibmi-types/api/Instance";
import { Extension, extensions } from "vscode";
let baseExtension: Extension<CodeForIBMi>|undefined;
/**
* This should be used on your extension activation.
*/
export function loadBase(): CodeForIBMi|undefined {
if (!baseExtension) {
baseExtension = (extensions ? extensions.getExtension(`halcyontechltd.code-for-ibmi`) : undefined);
}
return (baseExtension && baseExtension.isActive && baseExtension.exports ? baseExtension.exports : undefined);
}
/**
* Used when you want to fetch the extension 'instance' (the connection)
*/
export function getInstance(): Instance|undefined {
return (baseExtension && baseExtension.isActive && baseExtension.exports ? baseExtension.exports.instance : undefined);
}

Event listener

The Code for IBM i API provides an event listener. This allows your extension to fire an event when something happens in Code for IBM i.

const instance = getInstance();
instance.onEvent(`connected`, () => {
console.log(`It connected!`);
});

Available events

IDEvent
connectedWhen Code for IBM i connects to a system
disconnectedWhen Code for IBM i is disconnected from a system
deployLocationWhen a deploy location changes
deployWhen a deploy successfully finishes

APIs

Running commands with the user library list

Code for IBM i ships an API (via VS Code command) that can be used by an extension to execute a remote command on the IBM i.

It has a parameter which is an object with some properties:

interface CommandInfo {
/** describes what environment the command will be executed. Is optional and defaults to `ile` */
environment?: `pase`|`ile`|`qsh`;
/** set this as the working directory for the command when it is executed. Is optional and defaults to the users working directory in Code for IBM i. */
cwd?: string;
command: string;
}
  • Command can also use Promptable fields.
  • When executing a command in the ile or qsh environment, it will use the library list from the current connection.

The command returns an object:

interface CommandResult {
stdout: string;
stderr: string;
code: number;
}
const result: CommandResult = await vscode.commands.executeCommand(`code-for-ibmi.runCommand`, {
environment: `pase`,
command: `ls`
});
// or
const result = await vscode.commands.executeCommand(`code-for-ibmi.runCommand`, {
environment: `pase`,
command: `ls`
});

You can also provide a custom library list and current library when executing a command in the ile environment:

const detail: CommandResult = {
environment: `ile`,
command: `CRTBNDRPG...`,
env: {
// Space delimited library list
'&LIBL': 'LIBA LIBB LIBC'
'&CURLIB': 'LIBD'
}
}

Running SQL queries

Code for IBM i has a command that lets you run SQL statements and get a result back.

const instance = getInstance();
const rows = await instance.getContent().runSQL(`select * from schema.yourtable`);

Get members and streamfiles

It is possible for extensions to utilize the file systems provided by Code for IBM i.

openTextDocument returns a TextDocument .

Getting a member

//Member located on *SYSBAS
const doc = await vscode.workspace.openTextDocument(vscode.Uri.from({
scheme: `member`,
path: `/${library}/${file}/${name}.${extension}`
}));
//Member located on an iASP
const doc = await vscode.workspace.openTextDocument(vscode.Uri.from({
scheme: `member`,
path: `/${iasp}/${library}/${file}/${name}.${extension}`,
query: 'readonly=true' //Optional: open in read-only mode
}));

Getting a streamfile

const doc = await vscode.workspace.openTextDocument(vscode.Uri.from({
scheme: `streamfile`,
path: streamfilePath,
query: 'readonly=true' //Optional: open in read-only mode
}));

File system options

Both member and streamfile file systems support the following query parameters:

NameTypeDescription
readonlybooleanOpen the text editor in read only mode. Defaults to false.

Connect to a system

It is possible for your API to automate connecting to an IBM i instead of the user using the connection view.

const connectionData: ConnectionData = {...};
const connected: boolean = await vscode.commands.executeCommand(`code-for-ibmi.connectDirect`, connectionData);
if (connected) {
// do a thing.
} else {
// something went wrong.
}

VS Code integration

Right click options

It is possible for your extension to add right click options to:

  • objects in the Object Browser
  • members in the Object Browser
  • directories in the IFS Browser
  • streamfiles in the IFS Browser
  • much more

You would register a command as you’d normally expect, but expect a parameter for the chosen node from the tree view. Here is the sample for deleting a streamfile in the IFS Browser.

context.subscriptions.push(
// `node` is the object passed in directly from the IFS Browser.
vscode.commands.registerCommand(`code-for-ibmi.deleteIFS`, async (node) => {
if (node) {
//Running from right click
let result = await vscode.window.showWarningMessage(`Are you sure you want to delete ${node.path}?`, `Yes`, `Cancel`);
if (result === `Yes`) {
// directory using the connection API.
const connection = instance.getConnection();
try {
// Run a pase command
await vscode.commands.executeCommand(`code-for-ibmi.runCommand`, {
command: `rm -rf "${node.path}`,
environment: `pase`,
});
vscode.window.showInformationMessage(`Deleted ${node.path}.`);
this.refresh();
} catch (e) {
vscode.window.showErrorMessage(`Error deleting streamfile! ${e}`);
}
}
} else {
// If it's reached this point, it usually
// indicates that it's running from the command palette
}
})
);

Following that, we need to register the command so it has a label. We do this in package.json

{
"command": "code-for-ibmi.deleteIFS",
"title": "Delete object",
"category": "Your extension"
}

Finally, we add it to a context menu:

"menus": {
"view/item/context": [
{
"command": "code-for-ibmi.deleteIFS",
"when": "view == ifsBrowser",
"group": "yourext@1"
},
]
}

When adding your command to a menu context, there are lots of possible values for your when clause:

  • view can be ifsBrowser or objectBrowser.
  • viewItem can be different depending on the view:
    • for ifsBrowser, it can be directory or streamfile
    • for objectBrowser, it can be member (source member), object (any object), SPF (source file) or filter.

This allows your extension to provide commands for specific types of objects or specific items in the treeview.

Read more about the when clause on the VS Code docs website.

Views

Code for IBM i provides a context so you can control when a command, view, etc, can work. code-for-ibmi.connected can and should be used if your view depends on a connection. For example

This will show a welcome view when there is no connection:

"viewsWelcome": [{
"view": "git-client-ibmi.commits",
"contents": "No connection found. Please connect to an IBM i.",
"when": "code-for-ibmi:connected !== true"
}],

This will show a view when there is a connection:

"views": {
"scm": [{
"id": "git-client-ibmi.commits",
"name": "Commits",
"contextualTitle": "IBM i",
"when": "code-for-ibmi:connected == true"
}]
}

FAQs

Getting the temporary library

Please remember that you cannot use QTEMP between commands since each command runs in a new job. Please refer to instance.getConfig().tempLibrary for the user temporary library.

Is there a connection?

You can use instance.getConnection() to determine if there is a connection:

async getChildren(element) {
const connection = instance.getConnection();
let items: TreeItem[] = [];
if (connection) {
//Do work here...
} else {
items = [new vscode.TreeItem(`Please connect to an IBM i and refresh.`)];
}
return items;
}

connected context

If you refer to the Views section, you can make it so the view is only shown when connected. This means by the time the view is used, there should be a connection.

"views": {
"explorer": [{
"id": "yourIbmiView",
"name": "My custom View",
"contextualTitle": "Extension name",
"when": "code-for-ibmi:connected == true"
}]
}
"activationEvents": [
"onView:yourIbmiView"
]

Examples

See the following code bases for large examples of extensions that use Code for IBM i:

vscode-ibmi environment variable

We provide environment variables so Code for IBM i can be controlled by managed environments. See Variables.