cheat sheet

ISPF Edit

Deep dive into the ISPF editor — primary commands, line commands, BNDS/CC/MM column edits, ISREDIT macro services, profile management, and recovery.

ISPF Edit — Primary commands, line commands, macros, and column-mode editing

What it is

ISPF Edit (option 2 in ISPF, also reached via EDIT 'dsname' from TSO READY) is the full-screen editor that mainframe developers use for source, JCL, REXX, and parameter datasets — a sibling of View and Browse, but with destructive writes and a recoverable undo log. The editor is shipped by IBM as part of ISPF and has been the canonical mainframe code editor for decades. Reach for Edit whenever a dataset must be modified in place: changing JCL parameters, fixing a COBOL source line, tweaking a CLIST. For anything you only need to read, prefer View or Browse — they cannot accidentally destroy data and are usually available even when Edit is locked by another user.

This page is a deep companion to tso-ispf, focused exclusively on the Edit panel: every primary command, every line command, the column-mode editing pattern using BNDS/CC/MM, the ISREDIT macro programming interface, edit-profile management, and recovery.

z/OS 3.2 (GA 30 September 2025) ISPF Edit additions: PDSE V2 member generations are now first-class — EDIT 'pdse(member)' GEN(n) and BROWSE accept an explicit generation number, and a generation list is viewable for members with generations. The z/OS UNIX Directory List Utility offers a case-insensitive sort option for large directories. The z/OSMF Desktop Editor (APAR PH34912) lets dataset names and USS file paths render as clickable links — useful when staying off the 3270 entirely. For greenfield mainframe development, the Zowe Explorer VS Code extension is the IBM-recommended complement to ISPF Edit for IDE-resident workflows (datasets, USS files, JCL submit, TSO command issue) without replacing ISPF's local-edit semantics.

Entering Edit

Edit is opened either through an ISPF panel chain or directly from TSO. The fastest paths are option 2 (free-form dataset prompt), option 3.4 (DSLIST), or option =2 from any panel — = jumps the panel stack.

text
=2                            (* Edit panel — type dataset and press Enter   *)
=3.4                          (* DSLIST — then 'E' next to the dataset row    *)
EDIT 'ALICE.JCL.LIB(ALICEJ01)' (* From READY prompt — quoted = fully qualified *)
EDIT ALICE.SOURCE             (* Unquoted — your prefix is prepended           *)
EDIT JCL(NEWJOB) NEW          (* Allocate-and-edit a new member if missing     *)

Output: (none — opens the Edit panel)

From DSLIST you can also queue E against several rows; each opens in sequence, and END (PF3) moves to the next.

Edit screen anatomy

The Edit display has four regions you need to know cold: the command line, the prefix area (line numbers / line commands), the data area, and the message area. Understanding which keystroke goes where is the difference between fluent editing and constant RESET calls.

text
File  Edit  Edit_Settings  Menu  Utilities  Compilers  Test  Help
─────────────────────────────────────────────────────────────────
 EDIT       ALICE.JCL.LIB(ALICEJ01)               Columns 00001 00072
 Command ===>                                          Scroll ===> CSR
****** ***************************** Top of Data ******************************
000100 //ALICEJ01 JOB (ACCT),'ALICE DEV',CLASS=A,MSGCLASS=X,
000200 //         NOTIFY=&SYSUID,REGION=0M
000300 //STEP01   EXEC PGM=IEFBR14
000400 //NEWDS    DD  DSN=ALICE.NEW.DATA,
000500 //             DISP=(NEW,CATLG,DELETE),
000600 //             SPACE=(CYL,(5,2)),
000700 //             DCB=(RECFM=FB,LRECL=80)
****** **************************** Bottom of Data ****************************

Output: (none — exits 0 on success)

  • Command line (Command ===>) accepts primary commands like FIND, CHANGE, EXCLUDE, RESET.
  • Prefix area (the leftmost 6 chars, typically line numbers) accepts line commands like D, C5, RR, MM.
  • Data area is the visible record content from column 1 to the right margin (typically 72 for fixed-block 80, or LRECL for variable).
  • Scroll field (Scroll ===>) takes PAGE, HALF, CSR, DATA, or an integer.

Primary commands

Primary commands are typed on the Command ===> line and act on the buffer as a whole, the current cursor position, or a .label range. They are the equivalent of :command mode in vi or M-x in Emacs.

FIND / RFIND

FIND searches the buffer for a string starting at the cursor and stops at the first hit; RFIND (PF5) repeats the last FIND in the same direction. By default the search is case-insensitive and respects the current BOUNDS setting.

text
FIND ABEND                       (* find next "ABEND"                          *)
F ABEND FIRST                    (* first occurrence from top                  *)
F ABEND LAST                     (* last occurrence                            *)
F ABEND ALL                      (* show count, position at first hit          *)
F ABEND PREV                     (* search backward                            *)
F 'literal string'               (* preserve case and embedded spaces          *)
F C'CICS'                        (* same as above using "C" prefix             *)
F X'C8C5D3D3D6'                  (* hex search — finds the EBCDIC bytes "HELLO"*)
F P'#'                           (* picture: any numeric digit                 *)
F P'@'                           (* picture: any alphabetic char               *)
F P'='                           (* picture: any non-blank                     *)
F P'<'                           (* picture: any lowercase letter              *)
F P'>'                           (* picture: any uppercase letter              *)
F ABEND WORD                     (* whole word only                            *)
F ABEND PREFIX                   (* matches "ABENDED" but not "TABEND"         *)
F ABEND SUFFIX                   (* matches "TABEND" but not "ABENDED"         *)
F ABEND 10 30                    (* restrict to columns 10–30 for this find    *)
F ABEND .START .END              (* restrict to labeled range .START..END      *)

Output:

text
CHARS 'ABEND' found 3 times.

CHANGE / RCHANGE

CHANGE (alias C on the command line) substitutes one string for another. Like FIND, it accepts pictures, hex, and column/label ranges, plus an ALL keyword for global replace. RCHANGE (PF6) repeats the last change forward.

text
C OLDFLD NEWFLD                  (* change next OLDFLD to NEWFLD               *)
C OLDFLD NEWFLD ALL              (* change all                                 *)
C OLDFLD NEWFLD ALL 10 30        (* only within columns 10–30                  *)
C P'#' '0' ALL                   (* zap every digit to 0                       *)
C X'5A' X'7B' ALL                (* swap EBCDIC '!' (5A) for '#' (7B)          *)
C 'DSN=ALICE.OLD' 'DSN=ALICE.NEW' ALL
C 'PROD' 'TEST' ALL .DATAONLY    (* range limited by labels .DATAONLY..        *)

Output:

text
CHARS 'OLDFLD' changed 4 times.

When the new string is longer than the old, ISPF asks whether to push subsequent text right; if shorter, it asks whether to pull left. The default is governed by the PROFILE (STATS, NULLS, etc.) — see Edit profile below.

LOCATE / LOC

LOCATE jumps the cursor to a specific line. The argument can be an integer line number, a .label, a column-name like FIRST or LAST, or a relative offset.

text
LOC 100                          (* line number 100                            *)
LOC .ENTRY                       (* user-defined label set with .ENTRY in prefix*)
LOC FIRST                        (* top of data                                *)
LOC LAST                         (* bottom of data                             *)
LOC +50                          (* 50 lines forward                           *)
LOC -20                          (* 20 lines back                              *)
LOC X                            (* next excluded block                        *)
LOC NX                           (* next non-excluded line                     *)
LOC LABEL                        (* next labeled line                          *)
LOC CHA                          (* next changed line                          *)
LOC ERR                          (* next error line (e.g. compiled with err)   *)
LOC SPE                          (* next special line — marker line            *)
LOC ALL CHA .START .END          (* show all changed lines in labeled range    *)

Output: (none — the cursor moves to the matching line)

EXCLUDE / X / RESET / FLIP

EXCLUDE hides lines so you can focus on what remains; RESET brings them back. Combined with FIND, this is the canonical way to filter a 200,000-line dataset to just the rows you care about.

text
X ABEND ALL                      (* hide every line containing ABEND           *)
X ALL                            (* hide everything                            *)
X P'#' ALL                       (* hide all lines containing a digit          *)
RESET                            (* show all excluded lines, clear highlights  *)
RESET EXC                        (* show excluded — keep find/change highlights*)
RESET FIND                       (* clear find highlights only                 *)
RESET CHANGE                     (* clear change highlights only               *)
RESET LABEL                      (* clear all user labels                      *)
RESET COMMAND                    (* clear pending prefix commands              *)
FLIP                             (* swap visible <-> excluded                  *)
FLIP .S .E                       (* flip only within labeled range             *)

Output:

text
73 LINE(S) NOT DISPLAYED.

BOUNDS / BNDS

BOUNDS restricts FIND, CHANGE, SORT, and several line commands to a column range. Display the bounds line with the BNDS line command (covered below) and overtype the < and > markers; or set them numerically from the command line.

text
BOUNDS 16 71                     (* restrict to JCL operand columns 16–71      *)
BOUNDS *                         (* show current bounds                        *)
BOUNDS                           (* reset to default (1, record length)        *)

Output:

text
BOUNDS SET TO 16 71.

HEX

HEX toggles a 2-row hex display under each data line — top row holds the high nibble, bottom row the low nibble, both read top-down. Essential for diagnosing unprintable characters, tagging issues, or chasing EBCDIC vs ASCII mismatches.

text
HEX ON                           (* default: VERT — two rows under each data line *)
HEX ON VERT                      (* explicit vertical layout                   *)
HEX ON DATA                      (* hex appended to the right of each data line *)
HEX OFF                          (* turn off                                   *)

Output (a single record HELLO with HEX ON VERT):

text
000100 HELLO
       CCCCC
       8556F

The "C8 C5 D3 D3 D6" reads down: H=C8, E=C5, L=D3, L=D3, O=D6.

CAPS / NULLS / NUMBER / RENUM / UNNUM

These commands control how text you type is stored and how the prefix area is rendered. They are each one-line settings; combined with PROFILE (below) they form the editor's "vim modeline" equivalent.

text
CAPS ON                          (* fold every keystroke to uppercase          *)
CAPS OFF                         (* preserve mixed case (typical for REXX, PL/I)*)
NULLS ON                         (* trailing nulls — overtype past end of data *)
NULLS ON ALL                     (* convert trailing blanks to nulls on save   *)
NULLS OFF                        (* trailing blanks — append blocked at EOR    *)
NUMBER ON STD                    (* show standard sequence numbers cols 73–80  *)
NUMBER ON COB                    (* COBOL sequence numbers in cols 1–6         *)
NUMBER ON RELATIVE               (* relative numbering — recalc on every save  *)
NUMBER OFF                       (* hide sequence numbers (still in record)    *)
RENUM                            (* re-sequence existing numbers 100, 200, ... *)
RENUM 10 10                      (* start at 10, increment 10                  *)
UNNUM                            (* delete sequence numbers from the records   *)
AUTONUM ON                       (* renumber automatically on every save       *)

Output: (none — exits 0 on success)

TABS

TABS defines logical tab stops for inserting columnar data — useful for COBOL Area A/B or DDL alignment. Combined with the TS (Text Split) line command, it gives you a low-budget structured-text editor.

text
TABS ON                          (* enable tab processing                      *)
TABS 8 12 16 36 73               (* numeric stops at these columns             *)
TABS OFF
TABS *                           (* report current stops                        *)

Output: (none — exits 0 on success)

UNDO / REDO

UNDO reverses the most recent edit transaction; REDO re-applies it. SETUNDO STORAGE is the prerequisite — without it, undo is disabled by site default.

text
SETUNDO STORAGE                  (* enable in-memory undo for this session     *)
SETUNDO STG                      (* synonym                                    *)
SETUNDO FORCE                    (* enable even when RECOVERY is OFF           *)
SETUNDO OFF
UNDO                             (* roll back last logical change              *)
REDO                             (* re-apply the change just undone            *)

Output:

text
EDIT changes UNDONE.

MD — make dataline

MD strips the special line types — notes, MSG lines, info lines from MODEL, exclude-line markers — and turns them into real data records. Useful when you have just generated a JCL or COBOL skeleton via MODEL and want to commit it.

text
MD .ZF .ZL                       (* convert all info lines in labeled range    *)
MD ALL                           (* convert every non-data line in the file    *)

Output: (none — exits 0 on success)

Other useful primary commands

COLS, SORT, SUBMIT, SAVE, CANCEL, CREATE, REPLACE, and MOVE are common companions to the daily commands above.

text
COLS                             (* show a column ruler on the next line       *)
COL                              (* synonym                                    *)
SORT 1 80                        (* sort all records by columns 1–80 ascending *)
SORT 1 8 A 73 5 D                (* primary key 1-8 ASC, secondary 73-77 DESC  *)
SUBMIT                           (* submit the current buffer as JCL           *)
SUBMIT .S .E                     (* submit only the labeled range as a job     *)
SAVE                             (* save without leaving Edit                  *)
CANCEL                           (* abandon changes since last save            *)
CREATE ALICE.SNIP                (* copy selection or labeled range to dsname  *)
REPLACE ALICE.MEM(NEWMEM)        (* save selection to a new PDS member         *)
MOVE                             (* copy/move from another dataset/member      *)
COPY                             (* synonym for MOVE                           *)
EDIT 'ALICE.SECOND' SUBSET       (* open a sub-edit (split-screen alternative) *)

Output: (none — exits 0 on success)

Line commands

Line commands are typed in the prefix area (the 6-character field on the left). They act on a single line, a range (Dn, D5, Cn), or a paired block (DD...DD, CC...CC, MM...MM). When the cursor leaves the prefix area or you press Enter, all pending line commands run together.

Cursor and structural commands

text
I       (* insert one blank line BELOW                                          *)
I5      (* insert five blank lines                                              *)
TS      (* text-split — break the line at the cursor                            *)
TJ      (* text-join — join with the next line                                  *)
TE      (* text-entry — insert mode, ends with first blank line                 *)
TF      (* text-flow — reflow paragraph to right margin                         *)
COLS    (* place a column ruler under this line                                 *)
TABS    (* place a tab ruler under this line                                    *)
MASK    (* edit the mask used by INSERT — fixed columns auto-filled             *)
BNDS    (* place an editable BOUNDS ruler                                       *)
.LBL    (* place a user label "LBL" on this line                                *)

Output: (none — exits 0 on success)

Delete, copy, move, repeat, exclude

D, C, M, R, and X are the workhorses. Numeric suffix means "this many lines from here"; doubled letters delimit a block (DD...DD, etc.).

SingleBlockNumericMeaning
DDD...DDD5Delete
CCC...CCC3Copy (pair with A or B)
MMM...MMM2Move (pair with A or B)
RRR...RRR10Repeat
XXX...XXX4Exclude
SS5Show n hidden lines from this block
FShow first hidden line of this excluded block
LShow last hidden line of this excluded block
LCLC...LCLC3Lowercase
UCUC...UCUC3Uppercase
OOO...OOO5Overlay — paste over n lines (non-blank wins)
( ) < >(( )) << >>(5Shift left/right (data shift, no truncation if blanks)
[ ][[ ]][5Shift left/right (column shift — can truncate)
PPrint the line to the ISPF list dataset
WWrite to dataset (prompts)

Examples of usage:

text
000100 //JOB  ...
D00200 //STEP01 ...                (* D in prefix deletes this line             *)
000300 //STEP02 ...
R3 000400 //STEP03 ...              (* R3 repeats line 4 three times             *)
000500 //STEP04 ...

CC 000200                           (* start copy block here                    *)
000300
CC 000400                           (* end copy block — these 3 lines are copied*)
A  000500                           (* paste after this line                    *)

MM 000200                           (* start move block here                    *)
MM 000400                           (* end move block                           *)
B  000700                           (* paste before this line                   *)

X10 000200                          (* exclude 10 lines from here               *)

Output (after the R3 command runs):

text
000400 //STEP03 ...
'''''' //STEP03 ...
'''''' //STEP03 ...
'''''' //STEP03 ...

(Apostrophes in the prefix area mark inserted "ditto" lines until you save or assign sequence numbers.)

A / B / O — destinations

A (after), B (before), and O (overlay) are destination line commands. They are illegal on their own — every C/M/CC/MM requires a paired destination before you press Enter, or ISPF returns NO 'A' OR 'B' LINE COMMAND..

text
CC ...                              (* mark source block                        *)
CC ...
A                                   (* paste 1 copy after this line             *)

CC ...                              (* mark source block                        *)
CC ...
A5                                  (* paste 5 copies after this line           *)

MM ...                              (* mark source                              *)
MM ...
B                                   (* paste before, removing the source        *)

CC ...                              (* mark source                              *)
CC ...
OO ...                              (* overlay range                            *)
OO ...

Output: (none — exits 0 on success)

Overlay semantics — O / OO

Overlay merges the source into the destination column by column: for each column, the source character wins unless the source is a blank, in which case the destination character is preserved. This is the basis of column-mode editing (next section).

text
Source block (1 line):     ----+----X-----              (* blanks except col 10 *)
Destination block:         //OLD       INPUT
After OO/O paste:          //OLD     X INPUT

Output: (none — exits 0 on success)

Column-mode editing — BNDS + CC + MM + OO

Column-mode editing is the ISPF idiom for "edit just these columns across these rows" — vertically. It combines four commands: BNDS to limit the column range, CC...CC to copy a narrow source from one set of lines, and OO...OO to overlay it onto another set. The result is a true column-wise edit without a regex engine.

Recipe — change columns 16-25 across 50 lines

Suppose you have a JCL with 50 DD statements and you need to change a path component buried in columns 16-25 of every line. The conventional approach (CHANGE) only works if the substring is unique; column-mode editing works regardless.

text
Step 1 — set bounds to the columns you care about:
  Command ===> BOUNDS 16 25

Step 2 — at the line that already has the correct value, mark a 1-line CC block:
  CC 000100 //DD01 DD DSN=ALICE.NEW.LIB(MEMA),DISP=SHR
  CC 000100 //DD01 DD DSN=ALICE.NEW.LIB(MEMA),DISP=SHR

Step 3 — at the first and last lines that need to be overlaid, mark OO...OO:
  OO 000200 //DD02 DD DSN=ALICE.OLD.LIB(MEMB),DISP=SHR
   ...
  OO 000250 //DD50 DD DSN=ALICE.OLD.LIB(MEMZ),DISP=SHR

Output: (none — every overlaid row now reads ALICE.NEW in columns 16-25; everything outside the bounds is untouched)

Recipe — strip a column range without deleting lines

Combine BNDS with a CC block of a single blank line and OO over the targets to wipe columns clean while preserving line structure.

text
Command ===> BOUNDS 73 80

CC ........                        (* 1 blank line — source pad                *)
CC ........

OO 000100 ...                       (* every row in the OO block               *)
OO 000999 ...                       (* gets columns 73-80 blanked              *)

Output: (none — exits 0 on success)

Recipe — duplicate a 5-column "value" across N rows

This is how you set a constant value into a fixed slice of every line in a section without writing a REXX macro.

text
Command ===> BOUNDS 30 34

CC 000100 ...........TEST..        (* line containing "TEST " in cols 30-34   *)
CC 000100 ...........TEST..

OO 000200 ...                       (* range of rows where columns 30-34       *)
OO 000300 ...                       (* should be overlaid with "TEST "         *)

Output: (none — exits 0 on success)

Labels

Labels are user-defined symbolic names attached to a line (e.g. .S, .E, .ABEND). They appear in the prefix area and survive scrolling. Most primary commands accept a .label .label range to scope an action; LOCATE .label jumps to one.

text
.START 000100 //ALICEJ01 JOB ...    (* set label .START *)
.END   000999 //*END OF JOB         (* set label .END   *)

Command ===> X ALL .START .END      (* exclude only lines in that range        *)
Command ===> C 'PROD' 'TEST' ALL .START .END
Command ===> LOC .ABEND
Command ===> RESET LABEL            (* clear every user label                  *)

Output: (none — exits 0 on success)

Reserved system labels (set automatically and updated by ISPF) include .ZF (Z-First — top of file), .ZL (Z-Last — bottom), .ZFIRST, .ZLAST, and .ZCSR (current cursor line).

Edit profile

An edit profile groups settings (CAPS, NULLS, NUMBER, HEX, HILITE, RECOVERY, STATS, IMACRO, etc.) and is selected automatically by the dataset's last qualifier (JCL, COBOL, REXX, etc.) or the explicit PROFILE name command. Each user has up to 25 profiles cached in ISPF.ISPPROF.

text
PROFILE                          (* show current profile settings                 *)
PROFILE JCL                      (* switch to (or create) JCL profile             *)
PROFILE LOCK                     (* prevent ISPF from auto-switching profiles     *)
PROFILE UNLOCK
PROFILE RESET                    (* delete profile and recreate from site defaults*)
PROFILE NUMBER OFF
PROFILE CAPS OFF                 (* persist setting in current profile            *)
PROFILE HILITE JCL CURSOR        (* JCL highlight + cursor-line emphasis          *)
PROFILE RECOVERY ON              (* recoverable across crashes via journal DS     *)
PROFILE STATS ON                 (* maintain modification stats on members        *)
PROFILE IMACRO JCLINIT           (* auto-run macro JCLINIT on open                *)
PROFILE PACK ON                  (* compressed storage format                     *)
PROFILE NOTE ON                  (* show note lines from prior actions            *)

Output (PROFILE):

text
....JCL (FIXED - 80)....RECOVERY ON....NUMBER OFF STD....CAPS ON....
HEX OFF....NULLS ON....TABS OFF....AUTOSAVE ON PROMPT....AUTONUM OFF....
AUTOLIST OFF....STATS ON....PROFILE UNLOCK....IMACRO NONE....
PACK OFF....NOTE ON....HILITE JCL CURSOR FIND....

The profile name in the first parens (JCL) is what PROFILE switches between; you can have a JCL, COBOL, REXX, ASM, PLI, and arbitrary user profiles like MYNOTES.

Syntax highlighting — HILITE

HILITE controls real-time syntax coloring. The recognized languages cover everything common in z/OS development plus a AUTO mode that picks from the dataset's last qualifier.

text
HILITE JCL                       (* JCL syntax coloring                          *)
HILITE COBOL
HILITE PLI
HILITE ASM
HILITE REXX
HILITE SQL
HILITE PASCAL
HILITE C
HILITE HTML
HILITE OTHER                     (* generic — comment/string only                *)
HILITE AUTO                      (* match by dataset name                        *)
HILITE OFF
HILITE JCL CURSOR                (* JCL + highlight cursor line                  *)
HILITE JCL FIND                  (* JCL + highlight FIND hits                    *)
HILITE PAREN                     (* show matching parentheses                    *)
HILITE LOGIC                     (* highlight nested IF/DO blocks                *)
HILITE NOLOGIC

Output: (none — exits 0 on success)

Recovery

Edit recovery is a journal dataset (one per user) that captures every edit transaction. If your session abends or the system goes down, your next Edit on the same dataset offers to replay the journal. PROFILE RECOVERY ON is required.

text
PROFILE RECOVERY ON              (* enable per-profile                           *)
PROFILE RECOVERY OFF             (* disable                                      *)

On re-entry to a dataset whose journal has uncommitted edits, ISPF shows a RECOVERY? prompt:

text
Recovery has been requested.
This member was being edited during a previous session.
ENTER: continue recovery   ABORT: cancel recovery
DEFER: defer recovery

Enter re-applies every change; CANCEL (PF12) leaves the dataset untouched; DEFER keeps the journal entries for next time. The recovery dataset name is set in ISPF Settings (=0 → Edit Recovery), default userid.SPFTEMP1.CNTL.

Edit macros — ISREDIT services

An edit macro is a REXX, CLIST, or compiled program that uses the ISREDIT service interface to inspect and modify the buffer. Macros live in any dataset on SYSPROC or SYSEXEC, and run from the command line just like a primary command. They are the way to script ISPF Edit.

A minimal REXX macro that uppercases every line containing "TODO":

text
/* REXX */
"ISREDIT MACRO"                                   /* declare as macro            */
"ISREDIT (LAST) = LINENUM .ZL"                    /* total line count            */
do i = 1 to LAST
   "ISREDIT (LINE) = LINE " i                     /* get line text               */
   if pos("TODO", LINE) > 0 then do
       upper LINE                                 /* REXX upper                  */
       "ISREDIT LINE " i " = (LINE)"              /* write it back               */
   end
end
"ISREDIT (COUNT) = USER_STATE"                    /* save cursor/scroll          */
exit 0

Output: (none — exits 0 on success)

Common ISREDIT services

Every service is invoked via ADDRESS ISREDIT "command" (or "ISREDIT command" once ADDRESS ISREDIT is the default). Below is the working set; the full reference is in ISPF Edit and Edit Macros (SC19-3621).

text
ISREDIT MACRO                                 (* declare this REXX as a macro   *)
ISREDIT MACRO (P1 P2 P3)                      (* accept positional parameters   *)
ISREDIT MACRO PROCESS                         (* process pending line commands  *)

ISREDIT (LAST) = LINENUM .ZL                  (* number of last line in buffer  *)
ISREDIT (CUR)  = LINENUM .ZCSR                (* cursor line number             *)
ISREDIT (FIRST) = LINENUM .ZF                 (* first line                     *)
ISREDIT (LINE) = LINE n                       (* read line n into REXX var      *)
ISREDIT LINE n = (LINE)                       (* write REXX var into line n     *)
ISREDIT LINE_AFTER n = (NEW)                  (* insert NEW after line n        *)
ISREDIT LINE_BEFORE n = (NEW)                 (* insert NEW before line n       *)
ISREDIT DELETE n                              (* delete one line                *)
ISREDIT DELETE n m                            (* delete range n..m              *)
ISREDIT DELETE X ALL                          (* delete all excluded lines      *)
ISREDIT DELETE NX ALL                         (* delete all non-excluded lines  *)

ISREDIT FIND 'string' [FIRST|NEXT|LAST|PREV|ALL] [WORD|PREFIX|SUFFIX]
ISREDIT CHANGE 'old' 'new' ALL
ISREDIT EXCLUDE 'string' ALL
ISREDIT RESET
ISREDIT LOCATE n
ISREDIT LABEL n = .MYTAG                      (* set label .MYTAG on line n     *)

ISREDIT CURSOR = n                            (* move cursor to line n          *)
ISREDIT CURSOR = n c                          (* move cursor to (line n, col c) *)
ISREDIT (ROW COL) = CURSOR                    (* read cursor row & column       *)

ISREDIT (P1 P2 ... PN) = PARM                 (* accept primary command tokens  *)
ISREDIT (REC) = RECFM                         (* record format: F, V, U         *)
ISREDIT (LRECL) = LRECL                       (* logical record length          *)
ISREDIT (DSN) = DATASET                       (* full dataset(member) name      *)

ISREDIT SAVE                                  (* save changes without leaving   *)
ISREDIT END SAVE                              (* save and end                   *)
ISREDIT CANCEL                                (* abandon changes, end edit      *)
ISREDIT SUBMIT                                (* submit buffer as JCL           *)

ISREDIT BUILTIN cmd                           (* run editor cmd even if shadow  *)
ISREDIT MSG = 'message text'                  (* set the short message line     *)

Output: (none — exits 0 on success)

Running a macro

Put the macro REXX in a dataset allocated to SYSPROC (CLIST library) or SYSEXEC (REXX library) — typically userid.EXEC or a team library. From any Edit session, invoke it by name:

text
Command ===> TODOUC                           (* runs userid.EXEC(TODOUC)       *)
Command ===> TODOUC FIRST                     (* with a parameter              *)
Command ===> %TODOUC                          (* explicit "%" runs implicit EXEC*)

Output: (none — exits 0 on success)

To make a macro run automatically when you open a specific profile, set the IMACRO:

text
PROFILE IMACRO TODOUC

Output: (none — exits 0 on success)

Useful ready-made macros from site libraries

Most shops ship a starter set under SYS1.SISPMACS or similar. Names vary, but the common ones are:

MacroWhat it does
COMPARESide-by-side diff with another dataset (the underlying engine of SuperC)
INDENTIndents COBOL paragraphs or REXX do/end blocks consistently
STRIPRemoves trailing blanks and sequence numbers
LBOXDraws a box around a selected block using * and -
TOUCHTouch ISPF stats (modify date) without changing data
ADDREMAdd/remove a comment prefix to a labeled range

Common pitfalls

  1. CHANGE … ALL then CANCELCANCEL reverts since the last SAVE, so running a destructive change and then closing with PF3 saves it. Always SAVE before risky operations or set RECOVERY ON.
  2. CC block without A/B — pressing Enter clears all pending commands with an error. Always queue the destination on the same Enter as the source.
  3. HEX ON mixed with INSERT — typing in the hex area silently overlays the data area. Toggle hex off before inserting.
  4. CAPS ON on a REXX file — every line you touch goes to uppercase, breaking case-sensitive REXX variables. Always set PROFILE CAPS OFF for REXX, C, Java, Python, USS shell, and any mixed-case source.
  5. Forgetting BOUNDS * after column work — leftover bounds silently scope future CHANGE commands. BOUNDS * to inspect, BOUNDS (no args) to reset.
  6. No RECOVERY profile — a 3270 disconnect loses every keystroke since the last SAVE. PROFILE RECOVERY ON adds a small journal-dataset overhead but is worth it.
  7. Saving a record over LRECL — Edit truncates without warning when the new content overflows the right boundary. Watch the upper-right Columns nnnnn indicator.
  8. PROFILE LOCK set by accident — locks the profile so language-specific defaults stop working when you open a .COBOL member. PROFILE UNLOCK restores auto-switching.
  9. Running a macro that uses ADDRESS TSO without SIGNAL ON ERROR — the macro fails silently and the editor pretends success. Always wire SIGNAL ON ERROR and SAY RC in macro REXX while developing.
  10. UNDO after SAVE — once you save, the undo log is committed and earlier transactions are gone. Use SETUNDO STORAGE together with manual saves only at known-good points.

Real-world recipes

Replace a hard-coded dataset prefix across a PDS

Walk every member, switch a JCL prefix from ALICE.OLD to ALICE.NEW, save and move on. The fastest path is option 3.4M on the PDS row → enter a one-line edit macro per member, but SUPERCE with the change dataset option also works.

text
Macro: REPFX (in userid.EXEC)
─────────────────────────────
/* REXX */
"ISREDIT MACRO"
"ISREDIT CHANGE 'ALICE.OLD' 'ALICE.NEW' ALL"
"ISREDIT (CT) = CHANGE_COUNTS"
"ISREDIT MSG = 'REPFX: changed' word(CT,1) 'lines'"
"ISREDIT END SAVE"
exit 0

Output:

text
REPFX: changed 38 lines

Run it across an entire PDS from option 3.4:

text
Line command: M REPFX             (* member-list M command runs the macro      *)

Output: (none — exits 0 on success, one line per member)

Column-mode renumber on JCL DD statements

Renumber sequential DD names — DD01, DD02, ..., DD50 — that drifted out of order after a refactor. Set BOUNDS to the DD-name columns, mark the source line containing the lowest correct value, then OO over the run.

text
Command ===> BOUNDS 4 7

CC 000100 //DD01 DD ...
CC 000100 //DD01 DD ...

OO 000200 //DDxx DD ...
OO 000999 //DDxx DD ...

Then C 'DD01' 'DD02' to bump sequentially, or use a REXX macro that:
  - reads each line
  - extracts the trailing digits
  - rewrites the line with the next number

Output: (none — exits 0 on success)

Strip sequence numbers on a copied PDS member

A team member sent you a JCL fragment with COBOL sequence numbers in columns 73-80 that confuse SUBMIT. Wipe them in three keystrokes.

text
Command ===> BOUNDS 73 80
Command ===> C P'=' ' ' ALL
Command ===> BOUNDS

Output:

text
CHARS '=' (picture) changed 547 times.
BOUNDS SET TO 1 80.

Bulk-comment a block of REXX

Add /* ... */ to a marked block so you can test a code path without deleting it. The shifting commands > and < keep the leading characters intact.

text
000100 say 'before block'
)) 000101 if cond1 then
000102    do
000103       call sub
000104    end
)) 000110 say 'after block'        (* )) marks block end — shifts 1 column right*)

Now overtype the new leading column with *:

text
Command ===> X ALL
Command ===> F P'>' FIRST 1 1
Command ===> RESET
Command ===> C 'D ' '/*' 1 2 ALL .S .E   (* targeted column replace            *)

Output: (none — exits 0 on success)

Diff two members in a split-screen

Open the source member in Edit on screen 1; press PF2 to split; on screen 2 open the comparison member; toggle PF9 to swap. To merge a hunk from screen 2 to screen 1, label the lines on screen 2 with .S and .E, then CREATE to a scratch dataset and COPY into the target line.

text
PF2                              (* split horizontally at cursor row             *)
=2                               (* on the new screen go to Edit                 *)
EDIT 'ALICE.JCL.LIB(ALICEJ01)'   (* second member                                *)
PF9                              (* swap focus                                   *)

Output: (none — opens a second logical screen)

Find unprintable bytes in a copied dataset

A binary that should have been EBCDIC contains a few stray ASCII bytes (CR X'0D', LF X'0A'). Locate them precisely with hex search and let the cursor land on the offender.

text
Command ===> HEX ON
Command ===> X ALL
Command ===> F X'0D' ALL FIRST

Output:

text
CHARS X'0D' found 4 times.

Inspect each match in turn with PF5 (RFIND), and use the prefix D line command to delete the bad records.

Build a one-shot ISREDIT macro from inside Edit

You need a quick macro but do not want to allocate a new EXEC. Open a temporary dataset, write the REXX, save, run, throw away.

text
EDIT 'ALICE.EXEC(SCRATCH)'
... write the REXX ...
SAVE
END                              (* save and return                              *)
=2                               (* back into the dataset you want to edit       *)
Command ===> SCRATCH             (* invokes ALICE.EXEC(SCRATCH) as a macro       *)

Output: (none — exits 0 on success)

Macro: append today's date to every line containing "VERSION"

Combines ISREDIT FIND with DATE() REXX builtin to stamp each match with the current date.

text
/* REXX */
"ISREDIT MACRO"
TODAY = DATE("S")                                /* YYYYMMDD                    */
"ISREDIT (LAST) = LINENUM .ZL"
do i = 1 to LAST
   "ISREDIT (LINE) = LINE " i
   if pos("VERSION", LINE) > 0 then do
       NEW = strip(LINE) " " TODAY
       "ISREDIT LINE " i " = (NEW)"
   end
end
"ISREDIT MSG = 'Stamped lines with' TODAY"
exit 0

Output:

text
Stamped lines with 20260525

Macro: indent every nested block under "PROCEDURE DIVISION"

Walks every line below the first PROCEDURE DIVISION header and shifts code 2 columns right — a quick COBOL re-indent without leaving Edit.

text
/* REXX */
"ISREDIT MACRO"
"ISREDIT FIND 'PROCEDURE DIVISION' FIRST"
"ISREDIT (ROW) = CURSOR"
"ISREDIT (LAST) = LINENUM .ZL"
do i = ROW + 1 to LAST
   "ISREDIT (LINE) = LINE " i
   "ISREDIT LINE " i " = '  ' || LINE"
end
"ISREDIT MSG = 'Indented body of PROCEDURE DIVISION'"
exit 0

Output: (none — exits 0 on success)

Combine SORT and EXCLUDE for an ad-hoc report

You have a 50,000-line trace and want to see only the lines tagged WARNING or ERROR, sorted by timestamp in columns 1-10.

text
Command ===> X ALL
Command ===> F P'@@@@@@@' ALL 17 23           (* show rows whose cols 17-23 are alpha *)
Command ===> RESET FIND
Command ===> X 'INFO' ALL                     (* now exclude noise               *)
Command ===> SORT 1 10 A

Output:

text
73 LINE(S) NOT DISPLAYED.
SORT successful.

Sources