MiWorkplace - Editor for IBM i

Script Editor Example - ILEDocs Blocks

Since the last release (1.17.0) you can edit your source code programmatically. So what does this mean and how can you use it.

MiWorkplace has now a new view called Script Editor. There you can code some JavaScript which gets executed either on pressing the Execute button in the toolbar of the view or by using the keyboard shortcut CTRL+E.



But solely having the ability to write JavaScript is not that great at all. You can do that almost everywhere nowadays. What makes this much more useful is the fact that your script has access to some vital parts of the application, f. e. the current editor content (meaning: your program code (RPG, CL, DDS, ...), the text selection of the current editor and most noteably the abstract syntax tree (AST).

Abstract Syntax Tree

The abstract syntax tree is not a 1:1 view of your program code but an abstract view of the program code and in our case it covers only parts of your program. In MiWorkplace it powers functionality like editor hover support, content assist / auto completion and the outline but is also used in things like ILEDocs support.

The specific API on how to access these parts is described in the User Guide.

3rd Party Libraries

You can also use 3rd party Javascript libraries in your script. For example if you would want to use the Voca JavaScript string library you can include it in your script by using the load function like this:

load('/home/mihael/devel/js/voca.js');

Console

During the development of your script you probably don't want to test your script by changing your program code constantly just to have to undo your change because you have to tweak your script a bit more. With the introduction of the Script Editor view there is also the new Console view. The Console view shows everything you output from your script with the print function.

print("Text selection starting at " + selection.x);

Undo Changes

You can undo the changes of your script simply by using the Undo editor function (CTRL+Z).

Script Management

The view menu in the toolbar of the Script Editor view allows you to save and load your scripts to and from the filesystem. It also gives you easy access to the last used scripts.

Example

Here is a little example where an ILEDocs block is added before every procedure in the **FREE RPG code.

// load the 3rd party js library voca from the local filesystem
load("C:/users/schmidtm/downloads/voca.min.js");

// get all procedures from the AST
// note: this will not return the names of the procedures but Procedure objects.
var procedures = ast.listProcedures();

// we need to iterate through the procedure from the back to the front
// because we need to keep the line offsets intact
for (var i = procedures.size()-1; i >= 0 ;i--) {
  var p = procedures[i];

  // format the procedure name and output it to the console
  var procedureTitle = v.titleCase(v.words(p.getName()).join(" "));
  print(procedureTitle);

  // start the ILEDocs block
  var iledocsBlock = "///\n// " + procedureTitle + "\n//\n// TODO autogenerated\n";

  // the procedure object also contains all statements of the procedure.
  // we get the line number from the first statement so that we know where
  // to insert the ILEDocs block
  var statements = p.listStatements();
  var startLine = statements[0].getFirstLine();
  print("Line: " + startLine);

  var lineOffset = document.getLineOffset(startLine);
  print("Line offset: " + lineOffset);

  // we get the procedure interface from the procedure object
  // because we want to add some lines for each parameter and for
  // the return value
  var pi = p.getProcedureInterface();
  var parameters = pi.getParameters();
  if (!parameters.isEmpty()) {
    iledocsBlock += "//\n";

    for (var x = 0; x < parameters.size(); x++) {
      iledocsBlock += "// @param " + parameters[x].getName();

      if (isParameterOptional(parameters[x])) {
        iledocsBlock += " (optional)";
      }

      iledocsBlock += "\n";
    }
  }

  if (pi.getReturnValue()) {
    iledocsBlock += "//\n";
    iledocsBlock += "// @return TODO autogenerated\n";
  }

  // close the ILEDocs block
  iledocsBlock += "///\n";

  // output the whole block to the console
  print(iledocsBlock);

  // insert the ILEDocs block in the program code
  document.replace(lineOffset, 0, iledocsBlock);
}

// here we check if the parameter is optional,
// means has the keyword option *omit or *nopass
function isParameterOptional(parameter) {
  var options = parameter.getOptions();
  for (var i = 0; i < options.size(); i++) {
    if (options[i].toString() === "nopass") {
      return true;
    }
    else if (options[i].toString() === "omit") {
      return true;
    }
  }

  return false;
}


Script Engine Functionality

The script engine which is used here is the project Nashorn. You can find plenty of tutorials and articles about it by searching for the keywords java javascript nashorn.


Happy scripting!

Mihael

Tags : Script