Zowe: Setting up vscode before you start, so the editors work

You can configure vscode to say if the type of the is JCL, then display a line at column 80, so you can tell when your lines spill, and other clever things.

You need to install the support

  • IBM provides Z Open Editor, This provides a lot of function – some of which is chargeable. The editing for COBOL, PL/I, REXX, HLASM, and JCL is free. Once is it installed, you can click on the settings icon and display more information about what is supported.
  • Broadcom provides JCL language Support

Open vscode

  • Open the extensions window, Ctrl+shift+X
  • Search for the extension you want, and install it
  • Restart vscode

Configure the vscode settings

You need to do some vscode configuration to get the full benefit of Zowe explorer.

Display the file associations.

Use ctrl+shift+p and type Preferences: Open user settings (JSON).

For me this displayed a file which included

 "files.associations": {
"**/*.COBOL*{,/*}": "cobol",
"**/*.COB*{,/*}": "cobol",
"**/*.COBCOPY*{,/*}": "cobol",
"**/*.COPYBOOK*{,/*}": "cobol",
"**/*.COPY*{,/*}": "cobol",
"**/*.PL1*{,/*}": "pl1",
"**/*.PLI*{,/*}": "pl1",
"**/*.INC*{,/*}": "pl1",
"**/*.INCLUDE*{,/*}": "pl1",
"**/*.JCL*{,/*}": "jcl",

If I edit a member in a data set which matches *.JCL*, it will be flagged as a language jcl.

Display the language settings

Ctrl+shift+P and search for Preferences: specify language specific settings. This displays all of the languages known to this instance of vscode. Scroll down to jcl. If jcl is missing, you need to install the support. See You need to install the support above

Click on JCL. Information about JCL is displayed. There is a box with @lang:jcl above the display. If you type @lang:jcl ruler it will display information about the ruler parameter

Mine says

Editor: Rulers  (Modified elsewhere . Default value changed)
Render vertical rulers after a certain number of monospace characters. Use multiple values for multiple rulers. No rulers are drawn if array is empty.
Edit in settings.json

If you click on Edit in settings.json it will put you into an edit session.

I inserted

 "[jcl]": {
"editor.rulers": [10,16,80],
},

Save the files. Edit a JCL data set. The sessions should have vertical lines at 10,16, and 80.

Thanks

With thanks to Joshua Waters for getting me working, and answering my many questions.

How do I change all members of a PDS? Easy – use an edit macro

I looked on the internet, to find something that would allow me to make the same change to all members of a PDS, and there seemed to be several options, IPOUPDTE, CPPUPDTE, PDSUPDTE, written in assembler many years ago.

I had written an equivalent program in C, but I no longer have the source. I found it as quick to write a solution using Rexx and an ISPF edit, than to find a solution on the internet. The solution is much more flexible, and can do so much more.

The processing has two stages

  • Code to iterate over each member of the PDS, and invoke ISPF EDIT on each member
  • An edit macro to make the changes.

Code to iterate over each member

ISPF 3.4 DSLIST displays data sets

DSLIST - Data Sets Matching COLIN.J*       
Command ===>

Command - Enter "/" to select action
-------------------------------------------
AA COLIN.JCL
COLIN.JCL.DCOLLECT.OUTPUT

You can enter local commands at the front of each line. The commands can be ISPF special (D for Delete, C for Catalog, R for Rename), or TSO commands, where a TSO command can be a Rexx exec in the ISPEXEC concatenation. (You can use the TSO ISRDDN command to display the data sets allocated to your session)

I have a Rexx exec called AA.

Access the parameters passed to the rexx

/* rexx */                                           
ADDRESS ISPEXEC "VGET (ZDLDSN) SHARED"
ADDRESS ISPEXEC "VGET (ZDLCMD) SHARED"
ADDRESS ISPEXEC "VGET (ZDLLCMD) SHARED"
say "ZDLDSN " ZDLDSN
say "ZDLCMD " ZDLCMD
say "ZDLLCMD " ZDLLCMD

With the line command

Command - Enter "/" to select action  
--------------------------------------
AA 99 COLIN.JCL

The Rexx produces

ZDLDSN    COLIN.JCL
ZDLCMD AA 99
ZDLLCMD AA 99 'COLIN.JCL'
  • ZDLDSN is the data set name
  • ZDLCMD is the line command and any data
  • ZDLLCMD is the (Long) combined command and the data set

With the line command

aa 99 / Zyx

The dataset name is substituted for /, and the output is

ZDLDSN    COLIN.JCL
ZDLCMD AA 99 / Z
ZDLLCMD AA 99 'COLIN.JCL' Zyx

This means you can pass parameters to your Rexx.

Process every member

The data set name is in variable ZDLDSN. When you use it, you should quote it because your userid may/may not have prefix on, which puts your userid on the front of every data set you use. Without quotes, it could not find dataset COLIN.COLIN.JCL

  • The LMINIT command returns a handle in the DATAID(handle) variable, to refer to the data set. My handle is called data1.
  • The LMOPEN command opens the dataset associated with the handle.
  • The LMMLIST command iterates through the list, starting with a blank member name which indicates start with the first.
  • The EDIT command invokes ISPF edit on the member, and passes the name of an ISPF EDIT macro to use. In my case the macro is called FOREACH.
Address ispexec "LMINIT DATAID(data1) dataset('"ZDLDSN"')" 
if rc <> 0 then
do /* report the errors */
say ZERRSM ZERRLM
return 8
end
Address ispexec 'LMOPEN DATAID('data1') OPTION(INPUT)'
member = ' '
lmrc = 0
/*********************************************************************/
/* Loop through all members in the PDS, issuing the EDIT service for */
/* each. */
/*********************************************************************/
Do i = 1 by 1
Address ispexec 'LMMLIST DATAID('data1') OPTION(LIST),
MEMBER(MEMBER) STATS(NO)'
If rc = 8 then leave /* not found */
If rc <> 0 Then
do
say ZERRSM ZERRLM
leave
end
else
do
Address ispexec 'EDIT DATAID('data1') MEMBER('member')
MACRO(FOREACH)'
end
End
/*********************************************************************/
/* Free the member list and close the dataid for the PDS. */
/*********************************************************************/
Address ispexec 'LMMLIST DATAID('data1') OPTION(FREE)'
Address ispexec 'LMCLOSE DATAID('data1')'
Exit 0

From the information passed to the Rexx exec, you could pass the edit macro as a parameter, such as

AA / MYMAC 

I was just lazy and hard coded the macro name.

An edit macro to make the changes

My basic macro just reports the member name, and the size of the file

ADDRESS ISPEXEC 'ISREDIT MACRO' 
"ISREDIT (last) = LINENUM .ZLAST"
"ISREDIT (member ) = MEMBER"
"ISREDIT (curr,orig,concat)= DATASET"
say "foreach " member last curr
"ISREDIT END"
  • The LINENUM command returns the line number of the specified line. You can create your own line labels. ISPF provides .ZFIRST and .ZLAST .ZCSR (the line where the cursor is currently.
  • The MEMBER command returns the member name
  • The DATASET command returns the current name of the dataset (and other information)

You can now do conditional processing, if the data set name starts with… then change…; if the member name starts with… then change…

You can use standard ISPF commands for example

/* */ 
/* trace e */
ADDRESS ISPEXEC 'ISREDIT MACRO'

"ISREDIT X ALL "
"ISREDIT FIND '//' ALL"
"ISREDIT CHANGE 'IBMUSER' 'COLIN' 1 10 ALL NX"
return
"ISREDIT END"

Without the return statement in the code, the code makes the changes and exits, it invisibly edits all of the members. With the return statement this gives you the opportunity to review the changes and to use end or cancel to leave the edit session.

Whoops – what happened there

To test the macros I use ‘view’ of the member, to edit it, but not save any changes. I then executed the macro.
I was trying to change a VOLSER to a symbol.

/* */ 
ADDRESS ISPEXEC 'ISREDIT MACRO'
"ISREDIT (member ) = MEMBER"
say member
"ISREDIT SCAN OFF"
if substr(member,1,6) <> "IEASYM" then
do
"ISREDIT CHANGE 'A3PRD1' '&&SYSP1.' ALL "
"ISREDIT CHANGE 'A3PRD2' '&&SYSP2.' ALL "
"ISREDIT CHANGE 'A3PRD3' '&&SYSP3.' ALL "
"ISREDIT CHANGE 'A3PRD4' '&&SYSP4.' ALL "
"ISREDIT CHANGE 'A3PRD5' '&&SYSP5.' ALL "
"ISREDIT CHANGE 'A3RES2' '&&SYSR2.' ALL "
"ISREDIT CHANGE 'A3SYS1' '&&SYSS1.' ALL "
"ISREDIT CHANGE 'A3CFG1' '&&SYSC1.' ALL "
end
return
"ISREDIT END"f

I wanted to change A3PRD1 to the symbol &SYSP1. I had use use &&, and SCAN OFF. Without these, ISPF treats &SYSP1 as an ISPF symbol, cannot find it, so replaces it with a null.