summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ftdetect/pvx.vim2
-rw-r--r--ftplugin/pvx.vim14
-rw-r--r--indent/pvx.vim56
-rw-r--r--syntax/pvx.vim76
4 files changed, 148 insertions, 0 deletions
diff --git a/ftdetect/pvx.vim b/ftdetect/pvx.vim
new file mode 100644
index 0000000..8a07ca9
--- /dev/null
+++ b/ftdetect/pvx.vim
@@ -0,0 +1,2 @@
+" Detect ProvideX/PVX source files used by the Sage 100 connector.
+au BufRead,BufNewFile *.pvxsrc setfiletype pvx
diff --git a/ftplugin/pvx.vim b/ftplugin/pvx.vim
new file mode 100644
index 0000000..8134126
--- /dev/null
+++ b/ftplugin/pvx.vim
@@ -0,0 +1,14 @@
+" Filetype settings for ProvideX / PVX source files.
+if exists("b:did_ftplugin")
+ finish
+endif
+let b:did_ftplugin = 1
+
+setlocal commentstring=!\ %s
+setlocal comments=:!
+
+" formatpvx.pl indents with one literal tab per level; match that.
+setlocal noexpandtab
+setlocal tabstop=4
+setlocal shiftwidth=4
+setlocal softtabstop=4
diff --git a/indent/pvx.vim b/indent/pvx.vim
new file mode 100644
index 0000000..bd3931f
--- /dev/null
+++ b/indent/pvx.vim
@@ -0,0 +1,56 @@
+" Vim indent file
+" Language: ProvideX / PVX (Sage 100 business object source, *.pvxsrc)
+" Maintainer: native-sage-connector
+"
+" Mirrors the indent convention encoded in formatpvx.pl: a label, switch/
+" case/default, for, while, repeat, or a trailing "{" opens one level;
+" return, break, next, wend, until, else, end (def/switch/...), endif,
+" endcase, or a leading "}" closes one level for that line itself.
+
+if exists("b:did_indent")
+ finish
+endif
+let b:did_indent = 1
+
+setlocal indentexpr=GetPvxIndent()
+setlocal indentkeys=o,O,0{,0},!^F,=end,=next,=wend,=until,=else,=break,=default,=case,=endif,=endcase
+setlocal autoindent
+setlocal nosmartindent
+setlocal nocindent
+
+if exists("*GetPvxIndent")
+ finish
+endif
+
+" Strip leading indent, a trailing "! comment", and surrounding whitespace,
+" so keyword patterns can be anchored at column 0 regardless of existing indent.
+function! s:PvxStripComment(line)
+ let l = substitute(a:line, '\s*!.*$', '', '')
+ let l = substitute(l, '^\s*', '', '')
+ return substitute(l, '\s*$', '', '')
+endfunction
+
+" Lines whose presence means the *next* line gets one more indent level.
+let s:pvx_opener = '\c^\%(def\|switch\|case\|default\|for\|while\|repeat\)\>\|{\s*$\|^[A-Za-z_][A-Za-z0-9_.]*:\s*$'
+
+" Lines that get one *less* indent level applied to themselves.
+let s:pvx_closer = '\c^\%(end\|endif\|endcase\|next\|wend\|until\|else\|break\|return\)\>\|^}'
+
+function! GetPvxIndent()
+ let lnum = prevnonblank(v:lnum - 1)
+ if lnum == 0
+ return 0
+ endif
+
+ let ind = indent(lnum)
+
+ if s:PvxStripComment(getline(lnum)) =~ s:pvx_opener
+ let ind += &shiftwidth
+ endif
+
+ if s:PvxStripComment(getline(v:lnum)) =~ s:pvx_closer
+ let ind -= &shiftwidth
+ endif
+
+ return ind < 0 ? 0 : ind
+endfunction
diff --git a/syntax/pvx.vim b/syntax/pvx.vim
new file mode 100644
index 0000000..d7210a4
--- /dev/null
+++ b/syntax/pvx.vim
@@ -0,0 +1,76 @@
+" Vim syntax file
+" Language: ProvideX / PVX (Sage 100 business object source, *.pvxsrc)
+" Maintainer: native-sage-connector
+
+if exists("b:current_syntax")
+ finish
+endif
+
+" PVX keywords are case-insensitive in practice (mixed-case is common).
+syntax case ignore
+
+" --- Comments -------------------------------------------------------
+syn keyword pvxTodo TODO FIXME XXX NOTE contained
+syn match pvxComment "!.*$" contains=pvxTodo,@Spell
+
+" --- Strings & literals ---------------------------------------------
+" Doubled quotes ("") inside a string are a literal embedded quote.
+syn region pvxString start=/"/ skip=/""/ end=/"/
+
+" $$ is the "any/blank key" marker used in select/begin ranges.
+syn match pvxByteLiteral "\$\$"
+" $XX$ is a two-digit hex byte literal, e.g. $8A$ (field separator).
+syn match pvxByteLiteral "\$[0-9A-Fa-f][0-9A-Fa-f]\$"
+
+syn match pvxNumber "\<\d\+\(\.\d\+\)\?\>"
+
+" Pseudo-labels used as err=/dom= targets (*next, *break, *resume, ...)
+syn match pvxPseudoLabel "\*\h\w*"
+
+" Labels: BARE_WORD: alone on a line (optionally trailing a comment)
+syn match pvxLabel "^\s*[A-Za-z_][A-Za-z0-9_.]*:\s*\(!.*\)\=$"
+
+" Object method-call operator: obj'MethodName(
+syn match pvxMethodCall "'\h\w*"
+
+" --- Statements / control flow --------------------------------------
+syn keyword pvxConditional if then else switch case default
+syn keyword pvxRepeat for to step next while wend repeat until
+syn keyword pvxLabelKw break continue exit goto gosub return stop
+
+syn keyword pvxStatement
+ \ open close read write dim remove call select from begin where
+ \ sep iol rec key err dom execute drop object on error try catch
+ \ finally let print input rem
+
+syn keyword pvxStructure
+ \ def class like function perform local public global common
+ \ create delete required end
+
+syn keyword pvxOperator and or not
+
+" --- Built-in functions ----------------------------------------------
+syn keyword pvxFunction
+ \ nul pos tbl ucs lcs mid str stp pad varchar sub new find len
+ \ num evn clear msg dte lst vis dll max min val kec tim mod fib
+ \ lof eof dir exists chr asc int sqr rnd cvs cvt day abs kgen
+ \ ioc iol ios opt lpt ptr env exp log pi sgn dle fin fid dlm dod
+
+" --- Highlight links --------------------------------------------------
+hi def link pvxComment Comment
+hi def link pvxTodo Todo
+hi def link pvxString String
+hi def link pvxByteLiteral SpecialChar
+hi def link pvxNumber Number
+hi def link pvxPseudoLabel Special
+hi def link pvxLabel Label
+hi def link pvxMethodCall Function
+hi def link pvxConditional Conditional
+hi def link pvxRepeat Repeat
+hi def link pvxLabelKw Keyword
+hi def link pvxStatement Statement
+hi def link pvxStructure Structure
+hi def link pvxOperator Operator
+hi def link pvxFunction Function
+
+let b:current_syntax = "pvx"