- created plugin

This commit is contained in:
Erik Mertens 2023-07-31 09:22:36 +02:00
commit 2dba6368a5
18 changed files with 2113 additions and 0 deletions

0
.gitignore vendored Normal file
View File

151
README.md Normal file
View File

@ -0,0 +1,151 @@
rpgle.vim
=========
What does it contain?
---------------------
Free-Form ILE RPG bundle for vim, which contains syntax highlighting, syntax
folds, auto indent, more match words and a few sensible keys is remapped.
### Indent
One should modify `g:rpgle_indentStart` to adjust initial indentation level,
see `:help g:rpgle_indentStart` for more information.
There is support for automatic indentation. An example is:
dcl-proc myProc;
_
The cursor is located at `_` and the indent was inserted automatic when
pressing enter after `dcl-proc`. When typing `end-proc;` the indentation will
be decreased.
With procedure interfaces indentation will only happen if the procedure takes
an argument:
dcl-pi myProc;
_
If one type `end-pi;` the result will automatic become:
dcl-pi myProc;
end-pi;
`select`-`when`-`other`-`endsl` will be indented like this:
select;
when;
a();
when;
b();
other;
c();
_
As soon as `endsl` is typed it will be aligned with the initial `select;`.
`if`-`elseif`-`else`-`endif` will be indented like this:
if a = 1;
a();
elseif b = 1;
b();
else;
c();
_
When typing `endif` the indentation will be decreased.
Currently proper SQL indentation is missing:
exec sql
select *
from a
order by 1 desc;
See `:help ft-rpgle-indent`
### Syntax
Keywords, procedures and built-in functions will all be highlighted.
See `:help ft-rpgle-syntax`
### Syntax Folds
The following folds are supported:
- if -> endif
- dow -> enddo
- dou -> enddo
- for -> endfor
- select -> endsl
- dcl-proc -> end-proc
- begsr -> endsr
See `:help ft-rpgle-fold`
### Match Words
The following match words are supported:
- select -> when -> other -> endsl
- if -> elseif -> else -> endif
- dow -> iter -> leave -> enddo
- dou -> iter -> leave -> enddo
- begsr -> endsr
- dcl-proc -> return -> endproc
- dcl-pi -> end-pi
- monitor -> on-error -> endmon
See `:help ft-rpgle-match-words`
### Movements
rpgle.vim takes the liberty to bind `[[`, `]]`, `[]`, `][`, `gd`, `[{` and `]}`
and tried to make them useful for ILE RPG programming.
`[[` and `]]` will jump to the previous or next `dcl-proc` while `][` and `[]`
will jump to the previous or next `end-proc`.
`gd` will search for the word under the cursor from the previous `dcl-proc`.
`[{` and `]}` will jump to the associated block opener, i.e. standing inside an
`if` statement and pressing `[{` will bring you to the `if`, pressing `]}` will
bring you to the `endif`.
See `:help ft-rpgle-movements`
### Omni Completion
rpgle.vim provides a naive omni completion that will attempt to suggest
completion for compiler directives and header, declaration, calculation and
procedure specifications.
Calculation specification completion requires generated generated tags.
See `:h ft-rpgle-omni`
Contributing
------------
Make a [pull request](https://github.com/andlrc/rpgle.vim/pulls) or
[issue](https://github.com/andlrc/rpgle.vim/issues)
Self-Promotion
--------------
Like rpgle.vim? Then you might also like:
- [rpglectags](https://github.com/andlrc/rpglectags) which creates tags files
from ILE RPG,
- [rpgleman](https://github.com/andlrc/rpgleman) which provides man pages for
built-in functions keywords and more,
- and [rpglefmt](https://github.com/andlrc/rpglefmt) which will format Free Form ILE
RPG programs.
License
-------
Distributed under the same terms as Vim itself. See `:help license`

View File

@ -0,0 +1,98 @@
" Vim autoload file
" Language: Free-Form ILE RPG
" Maintainer: Andreas Louv <andreas@louv.dk>
" Last Change: Dec 04, 2018
" Version: 10
" URL: https://github.com/andlrc/rpgle.vim
function! rpgle#movement#NextSection(motion, flags, mode) range abort
let cnt = v:count1
let old_pos = line('.')
if a:mode ==# 'x'
normal! gv
endif
normal! 0
mark '
while cnt > 0
call search(a:motion, a:flags . 'W')
if old_pos == line('.')
execute 'norm!' a:flags =~# 'b' ? 'gg' : 'G'
endif
let old_pos = line('.')
let cnt = cnt - 1
endwhile
normal! ^
endfunction
function! rpgle#movement#NextNest(flags) abort
let flags = a:flags
let fn = a:flags ==# 'b' ? 'max' : 'min'
" We can get the list from ``b:match_words'' and just use first and last of
" each group
let poss = filter(map(split(b:match_words, ','),
\ { key, val ->
\ s:nextNestSearch(split(val, ':'), flags) }),
\ { key, val -> val > 0 })
let new_pos = call(fn, [poss])
if new_pos > 0
execute 'normal! ' . new_pos . 'G^'
endif
endfunction
function! s:nextNestSearch(kw, flags) abort
if a:kw[0] =~? 'if'
let middle = '\<\(else\|elseif\)\>'
elseif a:kw[0] =~? 'select'
let middle = '\<\(when\|other\)\>'
else
let middle = ''
endif
return s:findpair(a:kw[0], middle, a:kw[-1], a:flags)
endfunction
function! s:findpair(start, middle, end, flags) abort
" Find a pair which isn't inside a string nor comment
return searchpair(a:start, a:middle, a:end, a:flags . 'nW',
\ 'synIDattr(synID(line("."), col("."), 1), "name") =~? "string\\|comment"')
endfunction
function! rpgle#movement#Operator(ai) abort
let pairs = map(split(b:match_words, ','), { key, val ->
\ [split(val, ':')[0], split(val, ':')[-1]] })
" Find a pair which isn't inside a string nor comment
let poss = filter(map(pairs,
\ { key, val -> {"pair": val, "pos": s:findpair(val[0], '', val[1], 'b')} }),
\ { key, val -> val.pos > 0 })
let closest = { "index": 0, "pos": -1 }
let index = 0
for pos in poss
if pos.pos > closest.pos
let closest.pos = pos.pos
let closest.index = index
let closest.pair = pos.pair
endif
let index = index + 1
endfor
let match_words = b:match_words
let b:match_words = join(closest.pair, ':')
execute 'normal! ' . closest.pos . 'G^V'
normal %
let b:match_words = match_words
if a:ai == 'i'
normal! koj
endif
endfunction

428
autoload/rpgle/omni.vim Normal file
View File

@ -0,0 +1,428 @@
" Vim completion script
" Language: Free-Form ILE RPG
" Maintainer: Andreas Louv <andreas@louv.dk>
" Last Change: Jul 24, 2019
" Version: 10
" URL: https://github.com/andlrc/rpgle.vim
"
" Complete via tag files, this code is experimental
let s:keywords = [
\ ['alias', ['ds']],
\ ['align', ['ds']],
\ ['alt(', ['s', 'ds']],
\ ['altseq(', ['s', 'ds', 'subf', 'pi', 'pr', 'prp']],
\ ['ascend', ['s', 'ds', 'prp']],
\ ['based(', ['s', 'ds', 'pr']],
\ ['bindec(', ['s', 'subf', 'pip', 'prp']],
\ ['ccsid(', ['s', 'subf', 'pip', 'prp']],
\ ['char(', ['s', 'subf', 'pip', 'prp']],
\ ['class(', ['s', 'subf', 'pip', 'prp']],
\ ['const(', ['c']],
\ ['ctdata', ['s', 'subf']],
\ ['date', ['s', 'subf', 'pip', 'prp']],
\ ['date(', ['s', 'subf', 'pip', 'prp']],
\ ['descend', ['s', 'ds', 'prp']],
\ ['dim(', ['s', 'ds', 'pi', 'pip', 'pr', 'prp']],
\ ['dtaara', ['s', 'ds', 'subf']],
\ ['dtaara(', ['s', 'ds', 'subf']],
\ ['export', ['s', 'ds', 'proc']],
\ ['export(', ['s', 'ds', 'proc']],
\ ['ext', ['ds']],
\ ['extfld', ['subf']],
\ ['extfld(', ['subf']],
\ ['extname(', ['ds']],
\ ['extpgm', ['pr']],
\ ['extpgm(', ['pr']],
\ ['extproc', ['pr']],
\ ['extproc(', ['pr']],
\ ['extproc(', ['pr']],
\ ['float(', ['s', 'subf', 'pi', 'pip', 'pr', 'prp']],
\ ['graph(', ['s', 'subf', 'pi', 'pip', 'pr', 'prp']],
\ ['import', ['s', 'ds', 'proc']],
\ ['import(', ['s', 'ds', 'proc']],
\ ['int(', ['s', 'subf', 'pi', 'pip', 'pr', 'prp']],
\ ['ind', ['s', 'subf', 'pi', 'pip', 'pr', 'prp']],
\ ['inz', ['s', 'ds', 'subf']],
\ ['inz(', ['s', 'subf']],
\ ['len(', ['s', 'ds', 'subf', 'pr', 'prp']],
\ ['like(', ['s', 'subf', 'pi', 'pip', 'pr', 'prp']],
\ ['likeds(', ['ds']],
\ ['likefile(', ['prp']],
\ ['likerec(', ['ds', 'subf', 'pr', 'prp']],
\ ['noopt', ['s', 'ds']],
\ ['nullind', ['s', 'ds']],
\ ['nullind(', ['s', 'ds']],
\ ['object', ['s', 'subf', 'pi', 'pip', 'pr', 'prp']],
\ ['object(', ['s', 'subf', 'pi', 'pip', 'pr', 'prp']],
\ ['occurs(', ['ds']],
\ ['opdesc', ['pr']],
\ ['options(', ['pip', 'prp']],
\ ['overlay(', ['subf']],
\ ['packed(', ['s', 'subf', 'pi', 'pip', 'pr', 'prp']],
\ ['packeven', ['subf']],
\ ['perrcd(', ['s']],
\ ['pointer', ['s', 'subf', 'pi', 'pip', 'pr', 'prp']],
\ ['pointer(', ['s', 'subf', 'pi', 'pip', 'pr', 'prp']],
\ ['pos(', ['subf']],
\ ['prefix(', ['subf']],
\ ['psds', ['ds']],
\ ['qualified', ['ds']],
\ ['static', ['s', 'ds']],
\ ['static(', ['s', 'ds']],
\ ['template', ['s', 'ds']],
\ ['time', ['s', 'subf', 'pi', 'pip', 'pr', 'prp']],
\ ['time(', ['s', 'subf', 'pi', 'pip', 'pr', 'prp']],
\ ['timestamp', ['s', 'subf', 'pi', 'pip', 'pr', 'prp']],
\ ['timestamp(', ['s', 'subf', 'pi', 'pip', 'pr', 'prp']],
\ ['ucs2(', ['s', 'subf', 'pi', 'pip', 'pr', 'prp']],
\ ['uns(', ['s', 'subf', 'pi', 'pip', 'pr', 'prp']],
\ ['value', ['pip', 'prp']],
\ ['varchar(', ['s', 'subf', 'pi', 'pip', 'pr', 'prp']],
\ ['vargraph(', ['s', 'subf', 'pi', 'pip', 'pr', 'prp']],
\ ['varucs2(', ['s', 'subf', 'pi', 'pip', 'pr', 'prp']],
\ ['zoned(', ['s', 'subf', 'pi', 'pip', 'pr', 'prp']],
\ ]
let s:bifs = [
\ ['%abs', 'Absolute Value of Expression'],
\ ['%addr', 'Get Address of Variable'],
\ ['%alloc', 'Allocate Storage'],
\ ['%bitand', 'Bitwise AND Operation'],
\ ['%bitnot', 'Invert Bits'],
\ ['%bitor', 'Bitwise OR Operation'],
\ ['%bitxor', 'Bitwise Exclusive-OR Operation'],
\ ['%char', 'Convert to Character Data'],
\ ['%check', 'Check Characters'],
\ ['%checkr', 'Check Reverse'],
\ ['%data', 'document {:options}'],
\ ['%date', 'Convert to Date'],
\ ['%days', 'Number of Days'],
\ ['%dec', 'Convert to Packed Decimal Format'],
\ ['%dech', 'Convert to Packed Decimal Format with Half Adjust'],
\ ['%decpos', 'Get Number of Decimal Positions'],
\ ['%diff', 'Difference Between Two Date, Time, or Timestamp Values'],
\ ['%div', 'Return Integer Portion of Quotient'],
\ ['%editc', 'Edit Value Using an Editcode'],
\ ['%editflt', 'Convert to Float External Representation'],
\ ['%editw', 'Edit Value Using an Editword'],
\ ['%elem', 'Get Number of Elements'],
\ ['%eof', 'Return End or Beginning of File Condition'],
\ ['%equal', 'Return Exact Match Condition'],
\ ['%error', 'Return Error Condition'],
\ ['%fields', 'Fields to update'],
\ ['%float', 'Convert to Floating Format'],
\ ['%found', 'Return Found Condition'],
\ ['%graph', 'Convert to Graphic Value'],
\ ['%handler', 'handlingProcedure : communicationArea '],
\ ['%hours', 'Number of Hours'],
\ ['%int', 'Convert to Integer Format'],
\ ['%inth', 'Convert to Integer Format with Half Adjust'],
\ ['%kds', 'Search Arguments in Data Structure'],
\ ['%len', 'Get or Set Length'],
\ ['%lookupxx', 'Look Up an Array Element'],
\ ['%max', 'Maximum Value'],
\ ['%min', 'Minimum Value'],
\ ['%minutes', 'Number of Minutes'],
\ ['%months', 'Number of Months'],
\ ['%mseconds', 'Number of Microseconds'],
\ ['%nullind', 'Query or Set Null Indicator'],
\ ['%occur', 'Set/Get Occurrence of a Data Structure'],
\ ['%open', 'Return File Open Condition'],
\ ['%paddr', 'Get Procedure Address'],
\ ['%parms', 'Return Number of Parameters'],
\ ['%parmnum', 'Return Parameter Number'],
\ ['%parser', 'parser {: options}'],
\ ['%proc', 'Return Name of Current Procedure'],
\ ['%realloc', 'Reallocate Storage'],
\ ['%rem', 'Return Integer Remainder'],
\ ['%replace', 'Replace Character String'],
\ ['%scan', 'Scan for Characters'],
\ ['%scanr', 'Scan Reverse for Characters'],
\ ['%scanrpl', 'Scan and Replace Characters'],
\ ['%seconds', 'Number of Seconds'],
\ ['%shtdn', 'Shut Down'],
\ ['%size', 'Get Size in Bytes'],
\ ['%sqrt', 'Square Root of Expression'],
\ ['%status', 'Return File or Program Status'],
\ ['%str', 'Get or Store Null-Terminated String'],
\ ['%subarr', 'Set/Get Portion of an Array'],
\ ['%subdt', 'Extract a Portion of a Date, Time, or Timestamp'],
\ ['%subst', 'Get Substring'],
\ ['%this', 'Return Class Instance for Native Method'],
\ ['%time', 'Convert to Time'],
\ ['%timestamp', 'Convert to Timestamp'],
\ ['%tlookupxx', 'Look Up a Table Element'],
\ ['%trim', 'Trim Characters at Edges'],
\ ['%triml', 'Trim Leading Characters'],
\ ['%trimr', 'Trim Trailing Characters'],
\ ['%ucs2', 'Convert to UCS-2 Value'],
\ ['%uns', 'Convert to Unsigned Format'],
\ ['%unsh', 'Convert to Unsigned Format with Half Adjust'],
\ ['%xfoot', 'Sum Array Expression Elements'],
\ ['%xlate', 'Translate'],
\ ['%xml', 'xmlDocument {:options}'],
\ ['%years', 'Number of Years']
\]
function! rpgle#omni#Complete(findstart, base) abort
if a:findstart
" Locate the start of the item
let line = getline('.')
let start = col('.') - 1
if line =~? '^\s*/'
" Compiler directive
let s:type = 'compdir'
while start > 0
if line[start - 1] =~? '\S'
let start -= 1
else
break
endif
endwhile
elseif line =~? '^\s*ctl-opt\>'
" Header Specs
let s:type = 'hspec'
while start > 0
if line[start - 1] =~? '\k'
let start -= 1
else
break
endif
endwhile
elseif line =~? '^\s*dcl-'
" Declaration Specs
let s:type = 'dspec'
while start > 0
if line[start - 1] =~? '\k'
let start -= 1
else
break
endif
endwhile
else
" Assume Calculation Spec
let s:type = 'cspec'
let lastword = -1
while start > 0
if line[start - 1] =~# '\w'
let start -= 1
elseif line[start - 1] ==# '.'
let s:type = 'cspec_struct'
let member_start = start
let start -= 1
elseif line[start - 1] ==# '%'
let s:type = 'cspec_bif'
let start -= 1
else
break
endif
endwhile
if s:type ==# 'cspec_struct'
let s:struct = strpart(line, start, member_start - start - 1)
return member_start
endif
endif
let s:struct = ''
return start
endif
" Return list of matches:
if s:type ==# 'compdir'
return s:Compdir(a:base)
elseif s:type ==# 'hspec'
return s:HSpec(a:base)
elseif s:type ==# 'dspec'
return s:DSpec(a:base)
elseif s:type ==# 'cspec_struct'
return s:CSpecStruct(a:base, s:struct)
elseif s:type ==# 'cspec_bif'
return s:CSpecBIF(a:base)
elseif s:type ==# 'cspec'
return s:CSpec(a:base)
endif
endfunction
function! s:Compdir(base) abort
let line = getline('.')
echom a:base
" Filename completion
if line =~? '^\s*/\%(include\|copy\)\s\+'
let matches = globpath(&path, '*', 0, 1)
call filter(matches, { key, val -> val =~? '\.\%(rpgleinc\|mbr\)$' })
call map(matches, 's:Path2Suggetion(v:val)')
call filter(matches, { key, val -> val =~? '\%(^\|,\)' . a:base })
return map(matches, 's:Path2Item(v:val)')
else
return filter(['/copy', '/define', '/eject', '/else', '/elseif',
\ '/end-free', '/endif', '/eof', '/free', '/if', '/include',
\ '/restore', '/set', '/space', '/title', '/undefine'],
\ { key, val -> val =~? '^' . a:base })
endif
endfunction
function! s:HSpec(base) abort
return filter(['actgrp(', 'alloc(', 'altseq', 'alwnull(', 'aut(',
\ 'bnddir(', 'ccsid(', 'ccsidcvt(', 'copynest(', 'copyright(',
\ 'cursym(', 'cvtopt(', 'datedit(', 'datfmt(', 'dclopt(',
\ 'debug', 'decedit(', 'decprec(', 'dftactgrp(', 'dftname(',
\ 'enbpfrcol(', 'expropts(', 'extbinint', 'fixnbr(', 'fltdiv',
\ 'formsalign', 'ftrans', 'genlvl(', 'indent(', 'intprec(',
\ 'langid(', 'main(', 'nomain', 'openopt(', 'optimize(',
\ 'option(', 'pgminfo(', 'prfdta(', 'srtseq(', 'stgmdl(',
\ 'text(', 'thread(', 'timfmt(', 'truncnbr(', 'usrprf(',
\ 'validate('],
\ { key, val -> val =~? '^' . a:base })
endfunction
function! s:DSpec(base) abort
if a:base =~? 'dcl-'
let matches = filter(['dcl-s', 'dcl-c', 'dcl-ds', 'dcl-pr', 'dcl-proc',
\ 'dcl-pi'],
\ { key, val -> val =~? '^' . a:base })
else
" Keyword completion
let line = getline('.')
let type = substitute(line,
\ '^\s*dcl-\(s\|c\|ds\|pr\|proc\|pi\)\s\+\w\+\s\+.*',
\ '\1', '')
if type != line
let matches = []
for kw in s:keywords
if kw[0] =~? '^' . a:base && index(kw[1], type) > -1
call add(matches, kw[0])
endif
endfor
else
let matches = []
endif
endif
return map(matches, 's:Keyword2Item(v:val)')
endfunction
" Member completion via tags
function! s:CSpecStruct(base, struct) abort
let matches = []
let tags = taglist('^' . a:base)
let curbufnr = bufnr('%')
let struct = a:struct
" Resolve referenced data structure (``likeds(...)'')
let struct_tags = taglist('^' . struct . '$')
for tag in struct_tags
if complete_check()
break
endif
if tag['kind'] ==? 's' && has_key(tag, 'typeref')
let struct = substitute(tag['typeref'], 'struct:', '', '')
break
endif
endfor
for tag in tags
if complete_check()
break
endif
" Remove static matches in other files.
if tag['static'] && bufnr('%') != bufnr(tag['filename'])
continue
endif
" Remove anything but members
if tag['kind'] !=? 'm'
continue
endif
" Remove members from other data structures
if tag['struct'] !=? struct
continue
endif
call add(matches, s:Tag2Item(tag))
endfor
return matches
endfunction
function! s:CSpecBIF(base) abort
let matches = []
for bif in s:bifs
if bif[0] =~? '^' . a:base
call add(matches, s:BIF2Item(bif))
endif
endfor
return matches
endfunction
" Keyword completion via tags
function! s:CSpec(base) abort
let matches = []
let tags = taglist('^' . a:base)
let curbufnr = bufnr('%')
for tag in tags
if complete_check()
break
endif
" Remove static matches in other files.
if tag['static'] && curbufnr != bufnr(tag['filename'])
continue
endif
" Remove members
if tag['kind'] ==? 'm'
continue
endif
call add(matches, s:Tag2Item(tag))
endfor
return matches
endfunction
function! s:Path2Suggetion(path) abort
let path = substitute(a:path,
\ '^.\{-}\<qrpglesrc.file/\(\w\+\).\%(mbr\|rpgleinc\)$', '\1', '')
if path == a:path
let path = substitute(a:path,
\ '^.\{-}\<\(\w\+\).file/\(\w\+\).\%(mbr\|rpgleinc\)$',
\ '\1,\2',
\ '')
endif
if path == a:path
let path = a:path
endif
return path
endfunction
function! s:Path2Item(path) abort
return {
\ 'word': a:path
\ }
endfunction
function! s:Tag2Item(tag) abort
return {
\ 'word': a:tag['name'],
\ 'kind': a:tag['kind']
\ }
endfunction
function! s:Keyword2Item(kw) abort
return {
\ 'word': a:kw
\ }
endfunction
function! s:BIF2Item(bif) abort
return {
\ 'word': a:bif[0],
\ 'abbr': printf('%-10s - %s', a:bif[0], a:bif[1])
\ }
endfunction

95
demo.rpgle Normal file
View File

@ -0,0 +1,95 @@
/include a,b
/include c,d
dcl-ds abc likeds(def);
dcl-s a varchar(32);
a = %char(a, b);
b = %not_found(a);
c = found(hello);
dcl-proc a;
dcl-pi *n int(1);
qwerty const inz(1234) likeds(hello);
end-pi;
return *OFF;
end-proc;
dcl-pr hello;
world ind options(*nopass);
end-pr;
dcl-ds a;
a varchar(1);
end-ds;
dcl-ds likerec('hello');
a = *INRT;
begsr a;
hello();
endsr;
select;
when a = 1;
monitor;
a = 1 / 0;
on-error;
hello();
endmon;
doA();
b = *NULL;
when b = 1;
doB();
other;
doC();
endsl;
dow a < 4;
b();
c = *OFF;
enddo;
exec SQL declare parents cursor for pParent;
exec sql
select abs(abc), def
from qwer;
dcl-proc b;
dcl-pi *n;
a varchar(32);
end-pi;
hello();
end-proc;
dcl-proc c;
dcl-pi *n;
end-pi;
hello();
end-proc;
for i = 1 to 10;
doFor();
endfor;
if a = 1;
if b = 1;
doAB();
// hello
else;
world();
else;
doNOTABC():
endif;
else;
doQQ();
endif;

179
doc/rpgle.txt Normal file
View File

@ -0,0 +1,179 @@
*rpgle.txt* Free-Form ILE RPG
Author: Andreas Louv <andreas@louv.dk>
License: Same terms as Vim itself (see |license|)
INTRODUCTION *ft-rpgle*
This bundle provides syntax highlighting, syntax folds, auto indent, more
match words as well as mapping a few sensible keys.
VARIABLES *ft-rpgle-variables*
*g:rpgle_indentStart*
`g:rpgle_indentStart` Set the number of leading spaces that should be used
when no previous line is to be accounted for.
*g:rpgle_skipMapping*
`g:rpgle_skipMapping` Set to |v:true| to disable mappings defined in
|ft-rpgle-movements|, |ft-rpgle-operator-pending|
*g:rpgle_spellString*
`g:rpgle_spellString` Set to |v:false| to disable spell checking in string
constants.
FILETYPE DETECT *ft-rpgle-detect*
File ending with ".rpgle" and ".rpgleinc" are detected as ILE RPG files.
INDENT *ft-rpgle-indent*
Enable by adding the following to your |vimrc| >
:filetype indent on
<
SYNTAX *ft-rpgle-syntax*
Enable by adding the following to your |vimrc| >
:syntax enable
<
SYNTAX FOLDS *ft-rpgle-fold*
Settings |foldmethod| to 'syntax' to enable the following folds: >
if -> endif
dow -> enddo
dou -> enddo
for -> endfor
select -> endsl
dcl-proc -> end-proc
begsr -> endsr
<
MATCH WORDS *ft-rpgle-match-words*
Enable by adding the following to your |vimrc| >
:packadd! matchit
<
The following match words is supported: >
select -> when -> other -> endsl
if -> elseif -> else -> endif
dow -> iter -> leave -> enddo
dou -> iter -> leave -> enddo
for -> iter -> leave -> endfor
begsr -> endsr
dcl-proc -> return -> end-proc
dcl-pi -> end-pi
dcl-pr -> end-pr
monitor -> on-error -> endmon
<
MOVEMENTS *ft-rpgle-movements*
Enable by adding the following to your |vimrc| >
:filetype on
<
*ft-rpgle-[[*
[[ Jump to previous dcl-proc keyword
*ft-rpgle-]]*
]] Jump to next dcl-proc keyword
*ft-rpgle-[]*
[] Jump to previous end-proc keyword
*ft-rpgle-][*
][ Jump to next end-proc keyword
*ft-rpgle-gd*
gd Goto local Declaration. When the cursor is on a local
variable, this command will jump to its declaration.
Use |gD| to goto global declaration.
*ft-rpgle-[{*
[{ Jump back to the block opener at the start of the
current code block, i.e. pressing |[{| inside an
if-statement will jump to the if keyword.
*ft-rpgle-]}*
]} Jump forward to the block closer at the end of the
current code block, i.e. pressing |]}| inside an
if-statement will jump to the endif keyword.
OPERATOR PENDING *ft-rpgle-operator-pending*
Enable by adding the following to your |vimrc| >
:filetype on
<
a} *ft-rpgle-a}* *ft-rpgle-a{*
a{ *ft-rpgle-aB*
aB See |aB|
i} *ft-rpgle-i}* *ft-rpgle-i{*
i{ *ft-rpgle-iB*
iB See |iB|
INCLUDE *ft-rpgle-include*
'include' is set to match "/include" and "/copy". ".rpgle" and ".rpgleinc" is
added when following files with |gf|, or when searching included files with
|[I| and friends.
'includeexpr' is set to replace a "," with ".file/" i.e. >
/include myfile,mymbr -> myfile.file/mymbr.rpgleinc
<
It can be beneficial to setup 'path' accordantly: >
setlocal path=~/.cache/rpgleinc/qrpglesrc.file,~/.cache/rpgleinc
< And then download all headers to the respective directories inside
"~/.cache/rpgleinc".
I.e the header called "myhdr" located in "qrpglesrc" should be saved as
"~/.cache/rpgleinc/qrpglesrc.file/myhdr.rpgle".
One can use dd to download the files, i.e: >
$ dd if=/mnt_dir/QSYS.LIB/MY_LIB.LIB/QRPGLESRC.FILE/MYHDR.MBR \
of=~/.cache/rpgleinc/qrpglesrc.file/myhdr.rpgleinc \
bs=120 \
cbs=120 \
conv=ascii
<
Where 120 is the width of the header.
OMNI COMPLETION *ft-rpgle-omni*
Omni completion for compiler directives and header, declaration, calculation
and procedure specifications.
Omni completion can be called with |i_CTRL-X_CTRL-O|
OMNI COMPILER DIRECTIVES *ft-rpgle-omni-compdir*
A file found via 'path' will be suggested for "/copy" and "/include".
Only files ending with ".rpgleinc" and ".mbr" will be suggested.
Directories ending in ".file" will be preserved, with the exception of a
directory called "qrpglesrc.file" which will be removed. >
directory.file/file.mbr -> directory,file
qrpglesrc.file/file.mbr -> file
<
See |ft-rpgle-inclue| for a solution to downloading ILE RPG header files.
OMNI HEADER SPECIFICATION *ft-rpgle-omni-hspec*
Keywords like "bnddir" and "copyright" will be suggested.
An example would be: >
ctl-opt bnd<TAB> -> ctl-opt bnddir(
<
OMNI DECLARATION SPECIFICATION *ft-rpgle-omni-dspec*
Keywords like "static" and "dim" and types like "varchar" and "ind" will be
suggested for constants, standalone, data-structures, procedure-interfaces and
prototypes.
An example would be: >
dcl-s name var<TAB> -> dcl-s name varchar(
dcl-s name vargraph(
dcl-s name varucs2(
dcl-ds name qual<TAB> -> dcl-ds name qualified
<
OMNI PROCEDURE SPECIFICATION *ft-rpgle-omni-pspec*
Keywords like "export" will be suggested.
An example would be: >
dcl-proc name ex<TAB> -> export
-> export(
<
vim:tw=78:ts=8:ft=help:norl:

32
doc/tags Normal file
View File

@ -0,0 +1,32 @@
ft-rpgle rpgle.txt /*ft-rpgle*
ft-rpgle-[[ rpgle.txt /*ft-rpgle-[[*
ft-rpgle-[] rpgle.txt /*ft-rpgle-[]*
ft-rpgle-[{ rpgle.txt /*ft-rpgle-[{*
ft-rpgle-][ rpgle.txt /*ft-rpgle-][*
ft-rpgle-]] rpgle.txt /*ft-rpgle-]]*
ft-rpgle-]} rpgle.txt /*ft-rpgle-]}*
ft-rpgle-aB rpgle.txt /*ft-rpgle-aB*
ft-rpgle-a{ rpgle.txt /*ft-rpgle-a{*
ft-rpgle-a} rpgle.txt /*ft-rpgle-a}*
ft-rpgle-detect rpgle.txt /*ft-rpgle-detect*
ft-rpgle-fold rpgle.txt /*ft-rpgle-fold*
ft-rpgle-gd rpgle.txt /*ft-rpgle-gd*
ft-rpgle-iB rpgle.txt /*ft-rpgle-iB*
ft-rpgle-include rpgle.txt /*ft-rpgle-include*
ft-rpgle-indent rpgle.txt /*ft-rpgle-indent*
ft-rpgle-i{ rpgle.txt /*ft-rpgle-i{*
ft-rpgle-i} rpgle.txt /*ft-rpgle-i}*
ft-rpgle-match-words rpgle.txt /*ft-rpgle-match-words*
ft-rpgle-movements rpgle.txt /*ft-rpgle-movements*
ft-rpgle-omni rpgle.txt /*ft-rpgle-omni*
ft-rpgle-omni-compdir rpgle.txt /*ft-rpgle-omni-compdir*
ft-rpgle-omni-dspec rpgle.txt /*ft-rpgle-omni-dspec*
ft-rpgle-omni-hspec rpgle.txt /*ft-rpgle-omni-hspec*
ft-rpgle-omni-pspec rpgle.txt /*ft-rpgle-omni-pspec*
ft-rpgle-operator-pending rpgle.txt /*ft-rpgle-operator-pending*
ft-rpgle-syntax rpgle.txt /*ft-rpgle-syntax*
ft-rpgle-variables rpgle.txt /*ft-rpgle-variables*
g:rpgle_indentStart rpgle.txt /*g:rpgle_indentStart*
g:rpgle_skipMapping rpgle.txt /*g:rpgle_skipMapping*
g:rpgle_spellString rpgle.txt /*g:rpgle_spellString*
rpgle.txt rpgle.txt /*rpgle.txt*

9
ftdetect/binder.vim Normal file
View File

@ -0,0 +1,9 @@
" Vim ftdetect file
" Language: Binder Language
" Maintainer: Andreas Louv <andreas@louv.dk>
" Last Change: Mar 20, 2019
" Version: 2
" URL: https://github.com/andlrc/rpgle.vim
au BufNewFile,BufRead *.binder setlocal filetype=binder
au BufNewFile,BufRead *.BND setlocal filetype=binder

15
ftdetect/clle.vim Normal file
View File

@ -0,0 +1,15 @@
if exists('b:current_syntax')
finish
endif
let b:current_syntax = 'clle'
" syntax case ignore
" syntax iskeyword @,48-57,192-255,-,%,*,/,_
" syntax keyword clleCommand CHGVAR
" highlight link clleCommand Function
au BufNewFile,BufRead *.clle setlocal filetype=clle

13
ftdetect/rpgle.vim Normal file
View File

@ -0,0 +1,13 @@
" Vim ftdetect file
" Language: Free-Form ILE RPG
" Maintainer: Andreas Louv <andreas@louv.dk>
" Last Change: Mar 20, 2019
" Version: 8
" URL: https://github.com/andlrc/rpgle.vim
au BufNewFile,BufRead *.rpgle setlocal filetype=rpgle
au BufNewFile,BufRead *.sqlrpgle setlocal filetype=rpgle
au BufNewFile,BufRead *.rpgleinc setlocal filetype=rpgle
au BufNewFile,BufRead *.RPGLE setlocal filetype=rpgle
au BufNewFile,BufRead *.SQLRPGLE setlocal filetype=rpgle
au BufNewFile,BufRead *.RPGLEINC setlocal filetype=rpgle

17
ftplugin/binder.vim Normal file
View File

@ -0,0 +1,17 @@
" Vim ftplugin file
" Language: Binder Language
" Maintainer: Andreas Louv <andreas@louv.dk>
" Last Change: Mar 20, 2019
" Version: 1
" URL: https://github.com/andlrc/rpgle.vim
if exists('b:did_ftplugin')
finish
endif
let b:did_ftplugin = 1
setlocal suffixesadd=.binder
let b:match_words = '\<STRPGMEXP\>:\<ENDPGMEXP\>'

131
ftplugin/rpgle.vim Normal file
View File

@ -0,0 +1,131 @@
" Vim ftplugin file
" Language: Free-Form ILE RPG
" Maintainer: Andreas Louv <andreas@louv.dk>
" Last Change: Dec 19, 2018
" Version: 22
" URL: https://github.com/andlrc/rpgle.vim
if exists('b:did_ftplugin')
finish
endif
let b:did_ftplugin = 1
setlocal iskeyword+=-,%
setlocal shiftwidth=2
setlocal suffixesadd=.rpgle,.rpgleinc
" setlocal include=^\\s*/\\%(include\\\|copy\\)
setlocal include=^\s*\/\%(include\|copy\)
setlocal includeexpr=../substitute(v:fname,',','.file/','')
setlocal comments=s1:/*,mb:*,ex:*/,://,:*
setlocal commentstring=//%s
setlocal conceallevel=3
setlocal concealcursor=nvic
setlocal tabstop=2
setlocal expandtab
setlocal textwidth=100
setlocal colorcolumn=100
" ILE RPG is in case-sensitive
setlocal tagcase=ignore smartcase ignorecase
let b:match_words = '\<select\>:\<when\>:\<other\>:\<endsl\>'
\ . ',\<if\>:\<elseif\>:\<else\>:\<endif\>'
\ . ',\<do[uw]\>:\<iter\>:\<leave\>:\<enddo\>'
\ . ',\<for\>:\<iter\>:\<leave\>:\<endfor\>'
\ . ',\<for-each\>:\<iter\>:\<leave\>:\<endfor\>'
\ . ',\<begsr\>:\<endsr\>'
\ . ',\<dcl-proc\>:\<return\>:\<end-proc\>'
\ . ',\<dcl-pi\>:\<end-pi\>'
\ . ',\<dcl-pr\>:\<end-pr\>'
\ . ',\<monitor\>:\<on-error\>:\<endmon\>'
\ . ',\<dcl-ds\>:\<\%(likeds\|extname\|end-ds\)\>'
" section jumping {{{
nnoremap <script> <buffer> <silent> <Plug>RpgleGoToDeclaration
\ :<C-U>execute 'keepj normal [[/\<<C-r><C-w>\>/' . "\r"<CR>
" nnoremap <script> <buffer> <silent> <Plug>RpgleGoToDeclaration
" \ :<C-U>execute 'keepj normal [[/dcl-\(pi\|ds\|s\)\(\_s.\{-\}\)\{0,10}\zs<C-r><C-w>\ze\(\_s.\{-\}\)\{0,10}\_send-\1' . "\r"<CR>
nnoremap <script> <buffer> <silent> <Plug>RpgleNextProcStart
\ :<C-U>call rpgle#movement#NextSection('^\s*dcl-proc', '', '')<CR>
nnoremap <script> <buffer> <silent> <Plug>RpgleNextProcEnd
\ :<C-U>call rpgle#movement#NextSection('^\s*end-proc', '', '')<CR>
nnoremap <script> <buffer> <silent> <Plug>RpglePrevProcStart
\ :<C-U>call rpgle#movement#NextSection('^\s*dcl-proc', 'b', '')<CR>
nnoremap <script> <buffer> <silent> <Plug>RpglePrevProcEnd
\ :<C-U>call rpgle#movement#NextSection('^\s*end-proc', 'b', '')<CR>
xnoremap <script> <buffer> <silent> <Plug>XRpgleNextProcStart
\ :<C-U>call rpgle#movement#NextSection('^\s*dcl-proc', '', 'x')<CR>
xnoremap <script> <buffer> <silent> <Plug>XRpgleNextProcEnd
\ :<C-U>call rpgle#movement#NextSection('^\s*end-proc', '', 'x')<CR>
xnoremap <script> <buffer> <silent> <Plug>XRpglePrevProcStart
\ :<C-U>call rpgle#movement#NextSection('^\s*dcl-proc', 'b', 'x')<CR>
xnoremap <script> <buffer> <silent> <Plug>XRpglePrevProcEnd
\ :<C-U>call rpgle#movement#NextSection('^\s*end-proc', 'b', 'x')<CR>
if get(g:, 'rpgle_skipMapping', 0) == v:false
nmap <buffer> <silent> gd <Plug>RpgleGoToDeclaration
" nmap <buffer> <silent> gr <Plug>RpgleGoToReference
nmap <buffer> <silent> gr [I:let nr = input("Which one: ")<Bar>exe "normal " . nr ."[\t"<CR>
nmap <buffer> <silent> ][ <Plug>RpgleNextProcStart
nmap <buffer> <silent> ]] <Plug>RpgleNextProcEnd
nmap <buffer> <silent> [[ <Plug>RpglePrevProcStart
nmap <buffer> <silent> [] <Plug>RpglePrevProcEnd
xmap <buffer> <silent> ][ <Plug>XRpgleNextProcStart
xmap <buffer> <silent> ]] <Plug>XRpgleNextProcEnd
xmap <buffer> <silent> [[ <Plug>XRpglePrevProcStart
xmap <buffer> <silent> [] <Plug>XRpglePrevProcEnd
endif
" }}}
" Nest jumping {{{
nnoremap <script> <buffer> <silent> <Plug>RpglePrevBlock
\ :call rpgle#movement#NextNest('b')<CR>
nnoremap <script> <buffer> <silent> <Plug>RpgleNextBlock
\ :call rpgle#movement#NextNest('')<CR>
if get(g:, 'rpgle_skipMapping', 0) == v:false
nmap <buffer> [{ <Plug>RpglePrevBlock
nmap <buffer> ]} <Plug>RpgleNextBlock
endif
" }}}
" Operator Pending brackets {{{
noremap <script> <buffer> <silent> <Plug>RpgleAroundBlock
\ :<C-U>call rpgle#movement#Operator('a')<CR>
noremap <script> <buffer> <silent> <Plug>RpgleInnerBlock
\ :<C-U>call rpgle#movement#Operator('i')<CR>
if get(g:, 'rpgle_skipMapping', 0) == v:false
omap <buffer> a} <Plug>RpgleAroundBlock
omap <buffer> a{ <Plug>RpgleAroundBlock
omap <buffer> aB <Plug>RpgleAroundBlock
omap <buffer> i} <Plug>RpgleInnerBlock
omap <buffer> i{ <Plug>RpgleInnerBlock
omap <buffer> iB <Plug>RpgleInnerBlock
xmap <buffer> a} <Plug>RpgleAroundBlock
xmap <buffer> a{ <Plug>RpgleAroundBlock
xmap <buffer> aB <Plug>RpgleAroundBlock
xmap <buffer> i} <Plug>RpgleInnerBlock
xmap <buffer> i{ <Plug>RpgleInnerBlock
xmap <buffer> iB <Plug>RpgleInnerBlock
endif
" }}}
" Set completion with CTRL-X CTRL-O {{{
setlocal omnifunc=rpgle#omni#Complete
setlocal foldmethod=marker
" }}}
" vim: fdm=marker

53
indent/binder.vim Normal file
View File

@ -0,0 +1,53 @@
" Vim indent file
" Language: Binder Language
" Maintainer: Andreas Louv <andreas@louv.dk>
" Last Change: May 09, 2019
" Version: 1
" URL: https://github.com/andlrc/rpgle.vim
if exists('b:did_indent')
finish
endif
let b:did_indent = 1
setlocal indentexpr=GetBinderIndent()
setlocal indentkeys=o,O
setlocal indentkeys+=0*
setlocal indentkeys+=0=~strpgmexp,0=~endpgmexp
setlocal nosmartindent
let b:undo_indent = 'setlocal indentexpr< indentkeys< smartindent<'
if exists('*GetBinderIndent')
finish
endif
let s:cpo_save = &cpo
set cpo&vim
function! GetBinderIndent()
let cnum = v:lnum
let pnum = prevnonblank(cnum - 1)
let pind = indent(pnum)
let pline = getline(pnum)
let cline = getline(cnum)
" Add indent for opening keywords:
if pline =~ '^\s*\<strpgmexp\>'
return pind + shiftwidth()
endif
" Remove indent for closing keywords:
if cline =~ '^\s*\<endpgmexp\>'
return pind - shiftwidth()
endif
" If no match return the same indent as before:
return pind
endfunction
let &cpo = s:cpo_save
unlet s:cpo_save

140
indent/rpgle.vim Normal file
View File

@ -0,0 +1,140 @@
" Vim indent file
" Language: Free-Form ILE RPG
" Maintainer: Andreas Louv <andreas@louv.dk>
" Last Change: Nov 10, 2017
" Version: 18
" URL: https://github.com/andlrc/rpgle.vim
if exists('b:did_indent')
finish
endif
let b:did_indent = 1
setlocal indentexpr=GetRpgleIndent()
setlocal indentkeys=o,O
setlocal indentkeys+=0*
setlocal indentkeys+=0=~if,0=~elseif,0=~else,0=~endif
setlocal indentkeys+=0=~dou,0=~dow,0=~enddo
setlocal indentkeys+=0=~for,0=~endfor
setlocal indentkeys+=0=~for-each,0=~endfor
setlocal indentkeys+=0=~monitor,0=~on-error,0=~endmon
setlocal indentkeys+=0=~select,0=~when,0=~other,0=~endsl
setlocal indentkeys+=0=~dcl-proc,0=~end-proc
setlocal indentkeys+=0=~begsr,0=~endsr
setlocal indentkeys+=0=~dcl-pi,0=~end-pi
setlocal indentkeys+=0=~dcl-pr,0=~end-pr
setlocal indentkeys+=0=~dcl-ds,0=~end-ds
setlocal nosmartindent
let b:undo_indent = 'setlocal indentexpr< indentkeys< smartindent<'
if exists('*GetRpgleIndent')
finish
endif
let s:cpo_save = &cpo
set cpo&vim
function! GetRpgleIndent()
let cnum = v:lnum
let pnum = prevnonblank(cnum - 1)
" There is no lines to determinate indent, so use what is set in
" ``g:rpgle_indentStart'', check if ``**FREE'' is present or default to
" ``7''.
if pnum == 0
if exists('g:rpgle_indentStart')
return g:rpgle_indentStart
elseif getline(1) =~? '^\*\*FREE$'
return 0
else
return 7
endif
endif
let pind = indent(pnum)
let pline = getline(pnum)
let cline = getline(cnum)
" Continues comments should indent the ``*'' one space
if cline =~# '^\s*\*' && pline =~# '^\s*/\*' && pline !~# '\*/'
return pind + 1
endif
" Continues comments should de indent one space when ended
if pline =~# '^\s*\*.*\*/' || cline =~# '^\s*\\\*.*\*/'
return pind - 1
endif
" A ``when'' which follows a ``select'' should be indented:
" All other ``when'' should be de indented
if cline =~? '^\s*\<when\>'
return pline =~? '^\s*\<select\>;' ?
\ pind + shiftwidth() : pind - shiftwidth()
endif
" ``endsl'' has to go back one indent
if cline =~? '^\s*\<endsl\>' && pline =~? '^\s*\<when\>'
return pind - shiftwidth()
endif
" ``endsl'' have to de indent two levels:
if cline =~? '^\s*\<endsl\>'
return pind - shiftwidth() * 2
endif
" ``endsl'' does not have to change indentation
if cline =~? '^\s*\<endsl\>' && pline =~? '^\s*\<select\>'
return pind
endif
" ``dcl-pi'', ``dcl-pr'', and ``dcl-ds'' with no parameters should not
" indent the ``end-xx'':
if pline =~? '^\s*\<dcl-pi\>' && cline =~? '^\s*\<end-pi\>'
\ || pline =~? '^\s*\<dcl-pr\>' && cline =~? '^\s*\<end-pr\>'
\ || pline =~? '^\s*\<dcl-ds\>' && cline =~? '^\s*\<end-ds\>'
\ || pline =~? '^\s*\<if\>' && cline =~? '^\s*\<endif\>'
\ || pline =~? '^\s*\<monitor\>' && cline =~? '^\s*\<on-error\>'
return pind
endif
if pline =~? '^\s*\<dcl-pi\>.*\<end-pi\>'
echomsg 'test'
return pind
endif
" ``dcl-ds'' with ``likeds'' on the same line doesn't take a definition and
" should not do any indent:
if pline =~? '^\s*\<dcl-ds\>' && pline =~? '\<likeds\>'
return pind
endif
" ignore indentation, when the block is closed imediatly
if pline =~? '^\s*\%(if\|else\|elseif\|dou\|dow\|for\|for-each\|monitor\|on-error\|' .
\ 'on-error\|other\|dcl-proc\|begsr\|dcl-pi\|dcl-pr\|dcl-ds\)\>' &&
\ cline =~? '^\s*\<\%(endif\|enddo\|endfor\|endmon\|other\|else\|' .
\ 'elseif\|on-error\|end-pi\|end-proc\|endsr\|end-pr\|end-ds\)\>'
return pind;
endif
" Add indent for opening keywords:
if pline =~ '^\s*\%(if\|else\|elseif\|dou\|dow\|for\|for-each\|monitor\|on-error\|' .
\ 'on-error\|when\|other\|dcl-proc\|begsr\|dcl-pi\|dcl-pr\|dcl-ds\|on-exit\)\>'
return pind + shiftwidth()
endif
" Remove indent for closing keywords:
if cline =~ '^\s*\<\%(endif\|enddo\|endfor\|endmon\|other\|else\|' .
\ 'elseif\|on-error\|end-pi\|end-proc\|endsr\|end-pr\|end-ds\)\>'
return pind - shiftwidth()
endif
" If no match return the same indent as before:
return pind
endfunction
let &cpo = s:cpo_save
unlet s:cpo_save

28
syntax/binder.vim Normal file
View File

@ -0,0 +1,28 @@
" Vim syntax file
" Language: Binder Language
" Maintainer: Andreas Louv <andreas@louv.dk>
" Last Change: Mar 20, 2019
" Version: 1
" URL: https://github.com/andlrc/rpgle.vim
if exists('b:current_syntax')
finish
endif
let b:current_syntax = 'binder'
syntax iskeyword @,48-57,192-255,-,*,/,_
syntax keyword binderKeywords STRPGMEXP ENDPGMEXP EXPORT SYMBOL PGMLVL LVLCHK SIGNATURE
syntax match binderSpecial /'[^']\+'/
syntax match binderString /"[^"]\+"/
syntax match binderIdentifier /\w\+/
syntax keyword binderConstant *CURRENT *PRV
syntax sync fromstart
highlight link binderKeywords Keyword
highlight link binderSpecial Special
highlight link binderString String
highlight link binderIdentifier Identifier
highlight link binderConstant Constant

126
syntax/clle.vim Normal file
View File

@ -0,0 +1,126 @@
" if exists('b:current_syntax')
" finish
" endif
" let b:current_syntax = 'clle'
" syntax case ignore
" syntax iskeyword @,48-57,192-255,-,%,*,/,_
" syntax region clleProgramm matchgroup=clleBlock
" \ start=/\<PGM\>/
" \ end=/\<ENDPGM\>/
" \ contains=@clleNest
" syntax region clleMon matchgroup=clleBlock
" \ start=/\<MONMSG\>/
" \ end=/\<ENDDO\>/
" \ contains=@clleNest
" syntax region clleDclSpec display matchgroup=clleDclKeywords
" \ start=/\<DCL\>/
" \ end=/$/
" \ contains=clleDclProp,clleDclParms,clleParm,
" syntax region clleVarMut matchgroup=clleMutKeywords
" \ start=/\<CHGVAR\>/
" \ end=/$/
" \ contains=clleDclParms
" syntax match clleCmd /-\n\w\+/
" \ nextgroup=clleParms
" syntax match clleDclProp /\s*/ contained nextgroup=clleDclPropName
" syntax match clleDclPropName /&\k\+/ contained
" " syntax match clleParm /\w\+\ze(/ contained nextgroup=clleParenBalance
" syntax region clleParenBalance matchgroup=clleBIFBrackets
" \ start=/(/
" \ end=/)/
" \ contains=@clleNest
" syntax cluster clleNest contains=clleBlock,clleCommand,clleMon,clleDclSpec,clleTypes,clleVarMut,
" \ clleKeyParams
" syntax region clleComment matchgroup=clleCommentSigns
" \ start=/\/\*/
" \ end=/\*\//
" syntax keyword clleTypes contained *DEC *CHAR *YES *NO
" syntax keyword clleDclParms contained TYPE LEN VALUE VAR
" syntax match clleKeyParams /\*\w\+/ contained
" highlight link clleKeyParams SpecialKey
" highlight link clleCommentSigns Comment
" highlight link clleComment Comment
" highlight link clleCmd Function
" highlight link clleCommand Function
" " highlight link clleMon Conditional
" highlight link clleBlock Conditional
" highlight link clleDclKeywords Keyword
" highlight link clleMutKeywords Function
" highlight link clleDclPropName Constant
" highlight link clleDclParms Keyword
" highlight link clleTypes Type
" highlight link clleBIFBrackets Comment
" Vim syntax for CLLE
" This may use some of the Rexx code, but probably not.
" The Command/Program keyword lists will need to be modified as I come across
" more
syntax case ignore
syntax match clleLabel /^[^/*]*:/
highlight link clleLabel labels
syntax region clleComment start="/\*" end="\*/" contains=clleComment
highlight link clleComment comment
syntax match clleParam /[^ ]\{1}[^ %]*(/hs=s+0,he=e-1
highlight link clleParam type
syntax region clleString start=/'/ skip=/''/ end=/'/ oneline
highlight link clleString string
syntax match clleVariable /&[^) ]*/
highlight link clleVariable identifier
syntax keyword clleControl if do goto enddo else dofor return
highlight link clleControl keyword
syntax keyword clleCommand pgm dcl dclf monmsg chgvar subr endsubr callsubr call endpgm
\ rtvjoba rtvneta rcvf rtvusrprf
highlight link clleCommand keyword
syntax match clleKeyword /\*\w\+/
highlight link clleKeyword Special
syntax keyword clleProgram sndpgmmsg rmvlible addlible chkobj cpylib rtvdtaara
\ rtvmsg sndpgmmsg ovrprtf dltf crtpf crtlf clrpfm ovrdbf dltovr cpyf
\ crtddmf rclddmcnv crtsavf clrsavf savobj savlib rstobj rstlib ftp cf
\ clrlib rgzpfm dspffd chgdtaara ovrmsgf chgjob rmvmsg clof
\ sbmjob dspobjd opndbf cpysrcf dltmod movobj crtdtaq dltdtaq crtsqlrpgi
\ crtsrvpgm
highlight link clleProgram keyword
setlocal iskeyword+=%
syntax keyword clleBIF %address %addr %binary %bin %offset %ofs %substring %sst %switch
highlight link clleBIF BIF
setlocal iskeyword+=*
syntax keyword clleChoices *char *dec *int *defined *auto *based *blank
\ *eq *gt *ge *ne *lt *le *and *or *no *yes *nolist *nomax *nosrc
\ *last *first *dtaara *lib *libl *add *replace *savf *all
\ *cat *tcat *bcat *ip *lda *mdy *dmy *ymd *prv *ext *status
highlight link clleChoices preproc
" groups
highlight BIF guifg=red
highlight labels guifg=darkgrey

523
syntax/rpgle.vim Normal file
View File

@ -0,0 +1,523 @@
" Vim syntax file
" Language: Free-Form ILE RPG
" Maintainer: Andreas Louv <andreas@louv.dk>
" Last Change: Oct 21, 2019
" Version: 81
" URL: https://github.com/andlrc/rpgle.vim
if exists('b:current_syntax')
finish
endif
"runtime! syntax/sqlanywhere.vim
syntax include @esql syntax/sqlanywhere.vim
let b:current_syntax = 'rpgle'
syntax case ignore
syntax iskeyword @,48-57,192-255,-,%,*,/,_
" Comments {{{
syntax match rpgleLineComment '//.*' contains=rpgleSpecialComment
\ contains=@rpgleCommentProps
syntax region rpgleBracketedComment start='/\*'
\ end='\*/'
\ contains=@rpgleCommentProps
" syntax keyword rpgleSpecialComment BESCHREIBUNG AUTHOR ERSTELLDATUM PROGRAMMNUTZEN
" \ ÄNDERUNGSDATUM
syntax match rpgleSpecialComment '\(programmnutzen:\|beschreibung:\|author:\|erstelldatum:\|änderungsdatum:\|beispielaufruf:\|compilebefehl:\)'
syntax cluster rpgleComment contains=rpgleLineComment,rpgleBracketedComment,rpgleSpecialComment
syntax cluster rpgleCommentProps contains=rpgleTodo,@Spell
syntax keyword rpgleTodo contained TODO FIXME
syntax match rpgleDsReference '\(\w\+\.\)\+\w\+' contained contains=rpgleDsPath
syntax match rpgleDsReferenceSql ':\(\w\+\.\)\+\w\+' contained contains=rpgleDsPath
syntax match rpgleDsPath '\(\w\|\.\)\+\ze\.' contained nextgroup=rpgledsSeperator
syntax match rpgleDsSeperator '\.' contained nextgroup=rpgleDsItem
syntax match rpgleDsItem '\w\+' contained
syntax match rpgleSqlReference ':\zs\w\+' contained
syntax keyword db2SqlKeywords CLOSQLCSR DATFMT
syntax keyword db2SqlValues *ENDMOD *NONE *ISO
" }}}
" Compiler directive {{{
syntax keyword rpglePreProc **FREE
syntax keyword rpglePreProc /COPY /DEFINE /EJECT /ELSE /ELSEIF /END-FREE
\ /ENDIF /EOF /FREE /IF /INCLUDE /RESTORE /SET
\ /SPACE /TITLE /UNDEFINE /SET
\ nextgroup=rpglePreProcValue
syntax match rpglePreProcValue /.*/ contained display
" }}}
" Header Specs {{{
" CTL-OPT ... ;
syntax region rpgleCtlSpec matchgroup=rpgleKeywords
\ start=/\<CTL-OPT\>/
\ end=/;/
\ contains=@rpgleCtlProps
syntax cluster rpgleCtlProps contains=rpgleCtlKeywords,rpgleNumber,
\@rpgleString,rpgleConstant,rpgleError,
\rpgleCtlParanBalance
syntax region rpgleCtlParanBalance matchgroup=xxx
\ start=/(/
\ end=/)/
\ contains=@rpgleCtlProps
" Header Keywords
syntax keyword rpgleCtlKeywords contained
\ ALLOC ACTGRP ALTSEQ ALWNULL AUT BNDDIR CCSID
\ CCSIDCVT COPYNEST COPYRIGHT CURSYM CVTOPT
\ DATEDIT DATFMT DCLOPT DEBUG DECEDIT DECPREC
\ DFTACTGRP DFTNAME ENBPFRCOL EXPROPTS
\ EXTBININT FIXNBR FLYDIV FORMSALIGN FTRANS
\ GENLVL INDENT INTPREC LANGID MAIN NOMAIN
\ OPENOPT OPTIMIZE OPTION PGMINFO PRFDTA
\ SRTSEQ STGMDL TEXT THREAD TIMFMT TRUNCNBR
\ USERPRF VALIDATE REQPREXP
" }}}
" Declaration Specs {{{
" Numbers and Strings
syntax match rpgleNumber display
\ /\<-\=\%(\d\|\.\)\+\>/
syntax match rpgleError /\%(^\|\W\)\@1<='\_.\{-}'\W\@=/
syntax match rpgleString /'\([+-]\n\|''\|[^']\)*'/ contains=rpgleStringProps
syntax cluster rpgleString contains=rpgleString
if get(g:, 'rpgle_spellString', 1)
syntax cluster rpgleStringProps contains=@Spell
endif
" Constants
syntax keyword rpgleConstant *ALL *BLANK *BLANKS *ENTRY *HIVAL *LOVAL *NULL
\ *OFF *ON *ZERO *ZEROS *LOCK *ISO0 *HMS0 *EUR *UTF8
\ *SYS *OMIT *ALLOC *REQUIRE *WARN *PROC *DATA
" *IN01 .. *IN99, *INH1 .. *INH9, *INL1 .. *INL9, *INLR, *INRT
syntax match rpgleSpecialKey display /\%(\*IN0[1-9]\|\*IN[1-9][0-9]\)/
syntax match rpgleSpecialKey display /\*INH[1-9]/
syntax match rpgleSpecialKey display /\*INL[1-9]/
syntax match rpgleSpecialKey display /\*INU[1-8]/
syntax keyword rpgleSpecialKey *INLR *INRT
" Operators
syntax match rpgleOperator display /<>/
syntax match rpgleOperator display />=/
syntax match rpgleOperator display /<=/
syntax match rpgleOperator display /\<in\>/
syntax match rpgleOperator display /\<to\>/
syntax match rpgleOperator display /\<downto\>/
syntax match rpgleOperator display /\<by\>/
syntax match rpgleOperator display /\<out\>/
syntax match rpgleOperator display /[*=><+]/
syntax match rpgleOperator display /\<-\>/
" Standalone, Constant
syntax region rpgleDclSpec display matchgroup=rpgleDclKeywords
\ start=/\<DCL-[SCF]\>/
\ end=/$/
\ contains=rpgleDclProp
" Procedure Interface
syntax keyword rpgleError END-PI
syntax region rpgleDclSpec matchgroup=rpgleDclKeywords
\ keepend
\ start=/\<DCL-PI\>/
\ end=/\<END-PI\>/
\ contains=rpgleDclProp,rpgleDclPiName
\ fold
" Special PI Name
syntax keyword rpgleDclPiName *N
" Prototype
syntax keyword rpgleError END-PR
syntax region rpgleDclSpec matchgroup=rpgleDclKeywords
\ keepend
\ start=/\<DCL-PR\>/
\ end=/\(\<END-PR\>\|OVERLOAD\)/
\ contains=rpgleDclProp
\ fold
" Data Structure
syntax keyword rpgleError LIKEDS LIKEREC END-DS
syntax keyword rpgleError ;;
syntax region rpgleDclSpec matchgroup=rpgleDclKeywords
\ keepend
\ start=/\<DCL-DS\>/
\ end=/\<END-DS\>/
\ contains=rpgleDclProp
" These this syntax regions cannot be "display", even though it is on one line,
" as the rule above could be matched wrongly then.
syntax region rpgleDclSpec matchgroup=rpgleDclKeywords
\ start=/\<DCL-DS\>\ze.*LIKEDS/
\ start=/\<DCL-DS\>\ze.*LIKEREC/
\ end=/$/
\ contains=rpgleDclProp
" Declaration Types
syntax keyword rpgleDclTypes contained
\ BINDEC CHAR DATE DATE FLOAT GRAPH IND INT OBJECT
\ PACKED POINTER TIME TIMESTAMP UCS2 UCS2 UNS
\ VARCHAR VARGRAPH VARUCS2 ZONED
" Declaration Keywords
syntax keyword rpgleDclKeywords contained
\ ALIAS ALIGN ALT ALTSEQ ASCEND BASED CCSID
\ CLASS CONST CTDATA DATFMT DESCEND DIM DTAARA
\ EXPORT EXT EXTFLD EXTFMT EXTNAME EXTPGM
\ EXTPROC FROMFILE IMPORT INZ LEN LIKE LIKEDS
\ LIKEFILE LIKEREC NOOPT NULLIND OCCURS OPDESC
\ OPTIONS OVERLAY PACKEVEN PERRCD POS PREFIX
\ PSDS QUALIFIED RTNPARM STATIC TEMPLATE TIMFMT
\ TOFILE VALUE PRINTER USROPN OFLIND INDDS WORKSTN
\ SFILE INFDS SQLTYPE OVERLOAD
" Declaration Constants
syntax keyword rpgleDclSpecialKeys contained
\ *NOPASS *OMIT *VARSIZE *STRING *RIGHTADJ *AUTO *VAR *DCLCASE *EXACT
\ *TRIM
syntax keyword rpgleDclSqlTypes contained
\ CLOB CLOB_LOCATOR DBCLOB DBCLOB_LOCATOR
\ BLOB BLOB_LOCATOR
\ BINARY VARBINARY
\ XML_CLOB XML_DBCLOB XML_BLOB XML_LOCATOR
\ XML_BLOB_FILE XML_CLOB_FILE XML_DBCLOB_FILE
\ BLOB_FILE CLOB_FILE DBCLOB_FILE
\ ROW_ID RESULT_SET_LOCATOR
syntax region rpgleDclParenBalance matchgroup=rpgleDclBrackets
\ start=/(/
\ end=/)/
\ contains=@rpgleComment,rpgleDclSpecialKeys,rpgleDclSqlTypes,
\rpgleNumber,@rpgleString,
\rpgleConstant,rpgleError,
\rpgleDclParenBalance,rpgleBIF
syntax match rpgleDclProp /\s*/ contained nextgroup=rpgleDclPropName
syntax match rpgleDclPropName /\k\+/ contained nextgroup=rpgleDclPropTail
\ contains=@rpgleComment
syntax match rpgleDclPropTail /.\+/ contained
\ contains=@rpgleComment,rpgleDclTypes,
\rpgleDclKeywords,rpgleError,
\rpgleDclParenBalance
" }}}
" Calculation Specs {{{
" IF ... ENDIF
syntax keyword rpgleError ENDIF
syntax region rpgleIf matchgroup=rpgleConditional
\ start=/\<IF\>/
\ end=/\<ENDIF\>/
\ contains=@rpgleNest,rpgleElse
\ fold
" ELSE ELSEIF
syntax keyword rpgleError ELSE ELSEIF
syntax keyword rpgleElse contained ELSE ELSEIF
" NOT, AND, OR
syntax keyword rpgleConditional NOT AND OR
" DOW .. ENDDO, DOU .. ENDDO
syntax keyword rpgleError ENDDO
syntax region rpgleDo matchgroup=rpgleRepeat
\ start=/\<DO[WU]\>/
\ end=/\<ENDDO\>/
\ contains=@rpgleNest
\ fold
" FOR ... ENDFOR
syntax region rpgleFor matchgroup=rpgleRepeat
\ start=/\<FOR\>/
\ end=/\<ENDFOR\>/
\ contains=@rpgleNest
\ fold
syntax keyword rpgleError ENDFOR
syntax region rpgleForEach matchgroup=rpgleRepeat
\ start=/\<FOR-EACH\>/
\ end=/\<ENDFOR\>/
\ contains=@rpgleNest
\ fold
" ITER, LEAVE
syntax keyword rpgleRepeat contained ITER LEAVE
" MONITOR ... ENDMON
syntax keyword rpgleError ENDMON
syntax region rpgleMonitor matchgroup=rpgleConditional
\ start=/\<MONITOR\>/
\ end=/\<ENDMON\>/
\ contains=@rpgleNest,rpgleOnError
\ fold
" ON-ERROR
syntax keyword rpgleError ON-ERROR
syntax keyword rpgleOnError contained ON-ERROR
" ON-EXIT
syntax keyword rpgleOnExit contained ON-EXIT
" SELECT ... ENDSL
syntax keyword rpgleError ENDSL
syntax region rpgleSelect matchgroup=rpgleKeywords
\ start=/\<SELECT\>/
\ end=/\<ENDSL\>/
\ contains=@rpgleNest,rpgleWhenOther
\ fold
" WHEN, OTHER
syntax keyword rpgleError WHEN OTHER
syntax keyword rpgleWhenOther contained WHEN OTHER
" Exec SQL
syntax region rpgleSql matchgroup=rpgleKeywords
\ start=/\<EXEC\_s\+SQL\>/
\ end=/;/
\ contains=@esql,rpgleDsReferenceSql,rpgleSqlReference,db2SqlKeywords,
\ db2SqlValues
" Build In Functions
syntax match rpgleError /%\w\+/
syntax keyword rpgleBIF %ABS
\ %ADDR
\ %ALLOC
\ %BITAND
\ %BITNOT
\ %BITOR
\ %BITXOR
\ %CHAR
\ %CHECK
\ %CHECKR
\ %DATA
\ %GEN
\ %OKEDOKE
\ %DATE
\ %DAYS
\ %DEC
\ %DECH
\ %DECPOS
\ %DIFF
\ %DIV
\ %EDITC
\ %EDITFLT
\ %EDITW
\ %ELEM
\ %EOF
\ %EQUAL
\ %ERROR
\ %FIELDS
\ %FLOAT
\ %FOUND
\ %GRAPH
\ %HANDLER
\ %HOURS
\ %INT
\ %INTH
\ %KDS
\ %LEN
\ %LOOKUP
\ %LOOKUPLT
\ %LOOKUPLE
\ %LOOKUPGT
\ %LOOKUPGE
\ %MAX
\ %MIN
\ %MINUTES
\ %MONTHS
\ %MSECONDS
\ %NULLIND
\ %OCCUR
\ %OPEN
\ %PADDR
\ %PARMS
\ %PARMNUM
\ %PARSER
\ %PROC
\ %REALLOC
\ %REM
\ %REPLACE
\ %SCAN
\ %SCANR
\ %SCANRPL
\ %SECONDS
\ %SHTDN
\ %SIZE
\ %SQRT
\ %STATUS
\ %STR
\ %SUBARR
\ %SUBDT
\ %SUBST
\ %THIS
\ %TIME
\ %TIMESTAMP
\ %TLOOKUPxx
\ %TRIM
\ %TRIML
\ %TRIMR
\ %UCS2
\ %UNS
\ %UNSH
\ %XFOOT
\ %XLATE
\ %XML
\ %YEARS
\ %RANGE
\ %LIST
\ %UPPER
\ %LOWER
" Procedures, the match group is to avoid infinite recursion as a
" ``rpgleProcCall'' can be within another ``rpgleProcCall''
syntax match rpgleError /)/
syntax region rpgleProcCall matchgroup=rpgleProcCallName
\ start=/%\@1<!\<\w\+(/
\ end=/)/
\ contains=@rpgleProcArgs
\ nextgroup=rpgleDsSeperator
"syntax region rpgleDsArray \.\w\+
syntax cluster rpgleProcArgs contains=rpgleBIF,@rpgleComment,rpgleConstant,
\rpgleNumber,rpglePreProc,rpgleProcCall,
\rpgleSpecialKey,
\@rpgleString,rpgleError,rpgleParenBalance,rpgleDsReference,
\rpgleConstant
syntax keyword rpgleKeywords RETURN
\ SORTA
\ SORTD
\ WRITE
\ OPEN
\ CLOSE
\ EXFMT
\ DSPLY
\ READC
\ CLEAR
\ DATA-GEN
\ READ
\ CHAIN
\ UPDATE
\ EVAL
\ EVALR
\ DUMP
" BEGSR .. ENDSR
syntax keyword rpgleError ENDSR
syntax region rpgleSub matchgroup=rpgleKeywords
\ start=/\<BEGSR\>/
\ end=/\<ENDSR\>/
\ contains=@rpgleNest
\ fold
" EXSR
syntax keyword rpgleKeywords EXSR
" }}}
" Procedure Specs {{{
syntax region rpgleDclProcBody matchgroup=rpgleDclProc
\ start=/\<DCL-PROC\>/
\ end=/\<END-PROC\>/
\ contains=@rpgleDclProcNest
\ fold
syntax cluster rpgleDclProcNest contains=@rpgleNest,rpgleSub,rpgleDclSpec,
\rpgleDclProcName,rpgleError,rpgleOnExit
syntax keyword rpgleError END-PROC
" Procedure Name
syntax match rpgleDclProcName display contained skipwhite
\ /\%(DCL-PROC\s\+\)\@10<=\w\+/
\ nextgroup=rpgleDclProcExport
" Export
syntax keyword rpgleDclProcExport contained EXPORT
" }}}
syntax region rpgleParenBalance matchgroup=rpgleBIFBrackets
\ start=/(/
\ end=/)/
\ contains=@rpgleNest
" All nestable groups, i.e. mostly Calculation Spec keywords:
syntax cluster rpgleNest contains=rpgleBIF,@rpgleComment,rpgleConditional,
\rpgleConstant,rpgleDo,rpgleFor,rpgleForEach,rpgleIf,
\rpgleKeywords,rpgleMonitor,rpgleNumber,
\rpgleOperator,rpglePreProc,rpgleProcCall,
\rpgleRepeat,rpgleSelect,rpgleSpecialKey,
\rpgleSql,@rpgleString,rpgleError,
\rpgleParenBalance,rpgleDsReference
"syntax match rpgleDclProcName display skipwhite /\k*\ze\((.*)\)/
syntax sync fromstart
highlight link rpgleProcCallName Function
highlight link rpgleError Error
highlight link rpglePreProc PreProc
highlight link rpgleProc Function
highlight link rpgleSpecialKey SpecialKey
highlight link rpgleNumber Number
highlight link rpgleString String
highlight link rpgleOperator Operator
highlight link rpgleComment Comment
highlight link rpgleSpecialComment SpecialComment
highlight link rpgleTodo Todo
highlight link rpgleConstant Constant
highlight link rpgleConditional Conditional
highlight link rpgleRepeat Repeat
highlight link rpgleKeywords Keyword
highlight link rpgleSpecial Special
highlight link rpgleTypes Type
highlight link rpgleDsReference Operator
highlight link rpgleDsPath PreProc
highlight link rpgleDsItem Identifier
highlight link rpgleSqlReference Identifier
highlight link db2SqlKeywords Conditional
highlight link db2SqlValues PreProc
highlight link rpgleLineComment rpgleComment
highlight link rpgleBracketedComment rpgleComment
highlight link rpgleCtlKeywords rpgleKeywords
highlight link rpgleDclTypes rpgleTypes
highlight link rpgleDclSqlTypes rpgleTypes
highlight link rpgleDclKeywords rpgleKeywords
highlight link rpgleDclProc rpgleKeywords
highlight link rpgleDclProcExport rpgleKeywords
highlight link rpgleDclProcName rpgleProc
highlight link rpgleDclPiName rpgleSpecial
highlight link rpgleDclSpecialKeys rpgleSpecialKey
highlight link rpgleElse rpgleConditional
highlight link rpgleOnError rpgleKeywords
highlight link rpgleOnExit rpgleKeywords
highlight link rpgleWhenOther rpgleKeywords
highlight link rpgleBIF rpgleSpecial
highlight link rpgleBIFBrackets rpgleSpecial
highlight link rpgleDclBrackets Comment
highlight link rpgleDclPropName Constant
" vim: foldmethod=marker

75
test-err.rpgle Normal file
View File

@ -0,0 +1,75 @@
a = 'hello
x '' world
world
hello';
'error
here';
but not here, oh you didn't do it!
a = 'and error here
'
a = 'hello -
hello -
world';
dcl-pi;
end-pi;
end-pi;
dcl-pr;
end-pr;
end-pr;
dcl-ds;
end-ds;
end-ds;
dcl-ds likeds(abc);
likeds(abc);
if;
elseif;
else;
endif;
elseif;
else;
endif;
dow;
leave;
enddo;
enddo;
iter;
leave;
for;
endfor;
endfor;
monitor;
on-error;
endmon;
on-error;
endmon;
select;
when;
other;
endsl;
when
other;
endsl;
%char
%str
%err
abc()
abc())
)
begsr;
endsr;
endsr;
dcl-proc;
end-proc;
end-proc;
dcl-pi;
end-pi;
end-pi;