diff --git a/CHANGELOG.md b/CHANGELOG.md index afbedbf7..03cbdbc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,8 @@ ## `3.5.0` - Enhancement: Added CEEDUMP language mode. Files named `CEEDUMP.*` are automatically detected. It provides syntax highlighting and hover-help for headers, common messages, registers and more. 32-bit and 64-bit hex addresses are colored by byte significance to aid in pointer analysis. -- Enhancement: HLASM language mode now has hover-help and improved syntax highlighting +- Enhancement: HLASM language mode now has hover-help and improved syntax highlighting. +- Enhancement: Added hover documentation to the JCL language mode. Hovering over JCL statement keywords (JOB, EXEC, DD, PROC, IF, INCLUDE, JCLLIB, etc.) and parameter names (DSN, DISP, SYSOUT, SPACE, DCB, RECFM, LRECL, CLASS, REGION, COND, etc.) now displays a brief description of the keyword's purpose and common usage. No changes to syntax highlighting or theme. ## `3.4.0` diff --git a/webClient/src/app/editor/code-editor/monaco/hiliters/jcl.ts b/webClient/src/app/editor/code-editor/monaco/hiliters/jcl.ts index 10fc22ef..d9f79f1f 100644 --- a/webClient/src/app/editor/code-editor/monaco/hiliters/jcl.ts +++ b/webClient/src/app/editor/code-editor/monaco/hiliters/jcl.ts @@ -123,3 +123,99 @@ export const JCL_HILITE = { ] } }; + +// -- Hover documentation -- + +/** + * Hover documentation for JCL statement types, parameters, and common keywords. + * Keys are uppercase token strings as they appear in JCL source. + */ +export const JCL_HOVER_DOCS: Record = { + + // ---- Statement types ---- + JOB: '**JOB** -- Marks the beginning of a job. Identifies the job to the system, specifies accounting information, and sets job-level options such as CLASS, MSGCLASS, REGION, and NOTIFY.', + EXEC: '**EXEC** -- Executes a program or procedure. Use PGM= to name a load module directly, or specify a cataloged or in-stream PROC name.', + DD: '**DD** -- Data Definition. Describes a data set or I/O resource for a step. Required for every file opened by the program. Key parameters: DSN, DISP, UNIT, SPACE, DCB, SYSOUT.', + PROC: '**PROC** -- Begins an in-stream procedure definition, or (on an EXEC statement) names a cataloged procedure to invoke.', + PEND: '**PEND** -- Ends an in-stream procedure definition.', + IF: '**IF** -- Conditional expression. Tests the return code or abend status of preceding steps. Format: `// IF (condition) THEN`.', + THEN: '**THEN** -- Keyword following an IF condition. Statements between THEN and ELSE/ENDIF execute when the condition is true.', + ELSE: '**ELSE** -- Optional clause of an IF/THEN/ELSE/ENDIF construct. Statements between ELSE and ENDIF execute when the IF condition is false.', + ENDIF: '**ENDIF** -- Ends an IF/THEN/ELSE construct.', + INCLUDE: '**INCLUDE** -- Substitutes the contents of a JCL library member at the point of the statement. The member must contain valid JCL.', + JCLLIB: '**JCLLIB** -- Defines one or more private JCL procedure/include libraries to search before the system procedure libraries.', + OUTPUT: '**OUTPUT** -- Associates output characteristics (destination, forms, copies, etc.) with SYSOUT data sets. Referenced by DD statements via OUTPUT=*.name.', + SET: '**SET** -- Assigns a value to a symbolic parameter for use in the current JCL stream. The value replaces the symbol everywhere it appears in subsequent statements.', + CNTL: '**CNTL** -- Begins a control statement group passed directly to a program (e.g. DFSORT, IEBGENER control statements). Paired with ENDCNTL.', + ENDCNTL: '**ENDCNTL** -- Ends a CNTL block.', + XMIT: '**XMIT** -- Transmit JCL -- marks data to be transmitted to another node.', + COMMAND: '**COMMAND** -- Issues a z/OS operator command as part of job execution.', + EXPORT: '**EXPORT** -- Makes a symbol defined by SET available to called procedures.', + SCHEDULE: '**SCHEDULE** -- Associates a job with a scheduling environment for JES3.', + JOBGROUP: '**JOBGROUP** -- Begins a group of jobs that run together as a unit (JES3 job group).', + ENDGROUP: '**ENDGROUP** -- Ends a JOBGROUP definition.', + GJOB: '**GJOB** -- Defines a member job within a JOBGROUP.', + JOBSET: '**JOBSET** -- Defines a set of jobs within a JOBGROUP that share execution criteria.', + SJOB: '**SJOB** -- Names a specific job within a JOBSET.', + ENDSET: '**ENDSET** -- Ends a JOBSET definition.', + AFTER: '**AFTER** -- Specifies that a job or job group runs after another job or group completes.', + BEFORE: '**BEFORE** -- Specifies that a job or job group runs before another.', + CONCURRENT: '**CONCURRENT** -- Allows jobs in a group to run at the same time.', + + // ---- JOB statement parameters ---- + CLASS: '**CLASS** -- Job class (A-Z, 0-9). Determines which initiator can select the job. Configured by the installation.', + MSGCLASS: '**MSGCLASS** -- Output class for the job log (JES message data set). Typically A=held, X=print-and-delete, H=hold.', + MSGLEVEL: '**MSGLEVEL** -- Controls what appears in the job log. Format: `MSGLEVEL=(stmts,msgs)`. stmts: 0=JOB only, 1=all input, 2=only referenced. msgs: 0=none, 1=all JES and allocation messages.', + NOTIFY: '**NOTIFY** -- TSO user ID to notify when the job completes. The system sends a message to that user\'s terminal.', + REGION: '**REGION** -- Maximum virtual storage for a step or job. Format: `REGION=nnnK` or `REGION=nM`. 0M = no limit (up to system maximum). Also set on EXEC to override per-step.', + TIME: '**TIME** -- CPU time limit. Format: `TIME=(minutes,seconds)` or `TIME=nnn` (seconds). Terminate job if exceeded. Use TIME=NOLIMIT or TIME=1440 for no limit.', + ADDRSPC: '**ADDRSPC** -- Address space type: VIRT (virtual storage, default) or REAL (fixed real storage, discourages paging).', + COND: '**COND** -- Condition for skipping a step. Format: `COND=(code,operator)` or `COND=(code,operator,stepname)`. Operators: LT, LE, EQ, NE, GE, GT. Step is bypassed if condition is true. COND=EVEN or COND=ONLY for abend handling.', + ACCT: '**ACCT** -- Accounting information passed to the installation\'s accounting routine. Format is installation-defined.', + TYPRUN: '**TYPRUN** -- Special job execution mode: SCAN (syntax-check JCL only), HOLD (hold before execution), COPY (copy JCL to SYSOUT).', + RESTART: '**RESTART** -- Restart a failed job from a specified step: `RESTART=stepname` or `RESTART=stepname.procstep`.', + BYTES: '**BYTES** -- Limits the total bytes of SYSOUT output for the job. Exceeded jobs are cancelled.', + LINES: '**LINES** -- Limits the total lines of SYSOUT output for the job.', + PAGES: '**PAGES** -- Limits the total pages of SYSOUT output for the job.', + CARDS: '**CARDS** -- Limits the number of punch card images written to SYSOUT.', + PRTY: '**PRTY** -- JES2 job priority within the job class (0-15, higher = more priority).', + PERFORM: '**PERFORM** -- Performance group number assigned to the job for WLM/SRM scheduling.', + + // ---- EXEC statement parameters ---- + PGM: '**PGM** -- Names the load module (program) to execute. The system searches the JOBLIB, STEPLIB, and link pack. Example: `EXEC PGM=IEFBR14`.', + PARM: '**PARM** -- Character string passed to the program as its parameter (register 1 -> halfword length + data). Maximum 100 characters. Enclose in apostrophes if it contains special characters.', + DYNAMNBR: '**DYNAMNBR** -- Maximum number of data sets that can be dynamically allocated by this step.', + + // ---- DD statement parameters ---- + DSN: '**DSN (DSNAME)** -- Data Set Name. Identifies the data set. Multi-level names use periods as qualifiers (up to 44 characters total). Special values: `&&name` = temporary, `*` = inline data, `NULLFILE` / `DUMMY` = no I/O.', + DISP: '**DISP** -- Disposition. Format: `DISP=(status,normal,abnormal)`. Status: NEW, OLD, SHR, MOD. Normal/Abnormal: KEEP, DELETE, CATLG, UNCATLG, PASS. Example: `DISP=(NEW,CATLG,DELETE)`.', + UNIT: '**UNIT** -- Device type or group name for the data set. Examples: SYSDA (any direct-access), 3390 (DASD model), TAPE, VIO (virtual I/O). Can also specify a specific device address.', + VOL: '**VOL (VOLUME)** -- Volume serial or volume count. Format: `VOL=SER=volser` or `VOL=(PRIVATE,,n,SER=(v1,v2,...))`. Use to override catalog or specify multi-volume data sets.', + SYSOUT: '**SYSOUT** -- Directs output to the JES spool rather than a real data set. Format: `SYSOUT=class` (e.g. SYSOUT=*=same as MSGCLASS, SYSOUT=A=print). Can include writer name: `SYSOUT=(class,writer)`.', + SPACE: '**SPACE** -- Allocates DASD space. Format: `SPACE=(unit,(primary,secondary,directory))`. Unit: TRK, CYL, or blocksize. Example: `SPACE=(TRK,(10,5))` = 10 primary + 5 secondary tracks.', + DCB: '**DCB** -- Data Control Block attributes. Common sub-parameters: RECFM, LRECL, BLKSIZE, DSORG. Can reference another DD: `DCB=*.stepname.ddname`. Example: `DCB=(RECFM=FB,LRECL=80,BLKSIZE=27920)`.', + RECFM: '**RECFM** -- Record Format (DCB sub-parameter). Common values: F=fixed, FB=fixed-blocked, V=variable, VB=variable-blocked, U=undefined. Suffix A=ASA carriage control, M=machine carriage control.', + LRECL: '**LRECL** -- Logical Record Length in bytes (DCB sub-parameter). For variable records, includes the 4-byte RDW. Maximum: 32760 for VS, 32756 for VBS.', + BLKSIZE: '**BLKSIZE** -- Block size in bytes (DCB sub-parameter). Set to 0 to let the system determine the optimal block size. For tape: multiples of LRECL for fixed records.', + DSORG: '**DSORG** -- Data Set Organization (DCB sub-parameter). PS=sequential, PO=partitioned (PDS), IS=indexed sequential, DA=direct.', + DUMMY: '**DUMMY** -- Indicates a null DD -- no I/O actually occurs. The program opens and closes the file successfully but no data is read or written. Equivalent to DSN=NULLFILE,DISP=SHR.', + DDNAME: '**DDNAME** -- Defers a DD to be supplied later by dynamic allocation or by a referencing concatenation.', + LABEL: '**LABEL** -- Tape label type and sequence. Format: `LABEL=(seq,type,PASSWORD,RETPD=nnn,EXPDT=yyddd)`. Types: SL=IBM standard, NL=no label, SUL=standard+user, NSL=nonstandard.', + BUFNO: '**BUFNO** -- Number of I/O buffers to allocate for this data set. Larger values improve sequential I/O throughput at the cost of virtual storage.', + FREE: '**FREE** -- Controls when the data set is freed: END (at step end, default) or CLOSE (when the data set is closed). CLOSE is useful for long-running steps.', + AMP: '**AMP** -- Access Method Parameters for VSAM data sets. Provides VSAM control information that cannot be expressed through other DD parameters.', + AVGREC: '**AVGREC** -- Average record unit for space allocation: U=bytes, K=kilobytes, M=megabytes. Used with SPACE=(AVGREC,...).', + STORCLAS: '**STORCLAS** -- SMS Storage Class. Assigns the data set to a storage class defined in the SMS ACS routines for automatic storage management.', + MGMTCLAS: '**MGMTCLAS** -- SMS Management Class. Specifies backup, migration, and retention attributes for SMS-managed data sets.', + DATACLAS: '**DATACLAS** -- SMS Data Class. Provides default DCB and space attributes from an installation-defined template.', + KEYLEN: '**KEYLEN** -- Key length for ISAM or VSAM data sets (DCB sub-parameter).', + RKP: '**RKP** -- Relative Key Position: byte offset of the key within the record (DCB sub-parameter).', + EXPDT: '**EXPDT** -- Expiration date for the data set: EXPDT=yyddd (Julian) or EXPDT=yyyy/ddd.', + RETPD: '**RETPD** -- Retention period in days. The system calculates the expiration date as today + RETPD.', + SUBSYS: '**SUBSYS** -- Names a subsystem (e.g. a database manager) to handle I/O for this DD.', + PATH: '**PATH** -- HFS/zFS UNIX path name for z/OS UNIX files. Example: `PATH=\'/u/user/myfile.txt\'`.', + PATHMODE: '**PATHMODE** -- Permission bits for a newly created z/OS UNIX file (octal). Example: `PATHMODE=SIRWXU`.', + PATHOPTS: '**PATHOPTS** -- Open options for z/OS UNIX files: ORDWR (read/write), ORDONLY, OWRONLY, OCREAT, OTRUNC, etc.', + FILEDATA: '**FILEDATA** -- Indicates the data format for z/OS UNIX files: TEXT, BINARY, or RECORD.', +}; + diff --git a/webClient/src/app/editor/code-editor/monaco/monaco.config.ts b/webClient/src/app/editor/code-editor/monaco/monaco.config.ts index e7321eb7..dcf75380 100644 --- a/webClient/src/app/editor/code-editor/monaco/monaco.config.ts +++ b/webClient/src/app/editor/code-editor/monaco/monaco.config.ts @@ -19,7 +19,7 @@ import { BPXPRM_HILITE } from './hiliters/bpxprm'; import { CEEDUMP_HILITE, CEE_MESSAGES, CEEDUMP_HOVER_DOCS, CEE_RUNOPTS } from './hiliters/ceedump'; import { HLASM_HILITE, HLASM_DIRECTIVES, HLASM_MACRO_INSTS, HLASM_INSTRUCTIONS } from './hiliters/hlasm'; import { IEASYS_HILITE } from './hiliters/ieasys'; -import { JCL_HILITE } from './hiliters/jcl'; +import { JCL_HILITE, JCL_HOVER_DOCS } from './hiliters/jcl'; import { REXX_HILITE } from './hiliters/rexx'; @@ -557,6 +557,26 @@ export class MonacoConfig { monaco.editor.defineTheme('hlasm-dark', HLASM_DARK); monaco.languages.setMonarchTokensProvider('jcl', JCL_HILITE); + + monaco.languages.registerHoverProvider('jcl', { + provideHover: (model, position) => { + const word = model.getWordAtPosition(position); + if (!word) { return null; } + const token = word.word.toUpperCase(); + if (JCL_HOVER_DOCS[token]) { + return { contents: [{ value: JCL_HOVER_DOCS[token] }] }; + } + // Also check the line for parameter sub-keywords (RECFM=, LRECL=, etc.) + const line = model.getLineContent(position.lineNumber).toUpperCase(); + // Match paramname= context around cursor column + const col = position.column - 1; + const paramMatch = line.slice(0, col + token.length).match(/([A-Z]+)=?$/); + if (paramMatch && JCL_HOVER_DOCS[paramMatch[1]]) { + return { contents: [{ value: JCL_HOVER_DOCS[paramMatch[1]] }] }; + } + return null; + } + }); monaco.languages.setMonarchTokensProvider('rexx', REXX_HILITE); monaco.languages.registerHoverProvider('ceedump', {