chk.txt Utility used to check arguments of commands and functions
==============================================================================
CONTENTS chk-contents
1. Intro chk-intro
2. Functionality provided chk-functionality
2.1. Functions chk-functions
2.2. Checks chk-checks
2.3. Models chk-model
2.4. Transformations chk-trans
3. Example usage chk-usage
==============================================================================
1. Intro chk-intro
This plugin provides the ability to check whether function or command
arguments match specific model or whether some value matches specific model.
Features:
∙ Checks a list of arguments against specified model
∙ Checks a single value against specified model
∙ Provides a way to specify default values for optional arguments
∙ Provides a way to check a single value, convert it, and check again
Plugin requires load plugin to work.
==============================================================================
2. Functionality provided chk-functionality
This plugin provides two functions. Functions are accessed via dictionary
returned by load-func-getfunctions function.
------------------------------------------------------------------------------
2.1. Functions chk-functions
checkargument({check}, {argument}) :: Check -> a -> Bool
Checks data {argument} using check {check}. For possible {check}
arguments see chk-checks
checkarguments({model}, {arguments}) :: Model -> [a] -> Bool
Checks argument list {arguments} (it must be a single list!) using
model {model}. For possible {model} arguments see chk-model.
------------------------------------------------------------------------------
2.2. Checks chk-checks
All checks are lists of three or two elements. First element is the name of
a check. Second is an argument of the check. Third is optional and it contains
the error message displayed when the check fails.
Check name Check argument and description
in [a] (any list)
Checks whether {argument} is in list {checkargument}.
regex Regex (correct regular expression)
Checks whether {argument} is a string and matches regular
expression {checkargument}.
func (a -> Bool) (any function that takes {argument} and
returns 1 or 0)
Checks, whether function being supplied by {argument} as an
{argument} returns true. Note that this function must not echo any
warnings using :echoerr: they will be captured by :try and
check will fail.
type Int (any integer from 0 to 5)
Checks, whether type of {argument} is {checkargument}.
isfunc Bool (0 or 1)
Checks, whether {argument} is function reference and it is
callable. It is similar to chk-check-type when {checkargument}
is 2, but prevents from supplying function references that are not
callable (for example, if this reference points to script-local
function). If {checkargument} is 1, then check also accepts
strings with function names.
bool _ (argument is ignored)
Checks, whether {argument} is either 0 or 1.
eval String (any correct expression)
Checks, whether eval({checkargument}) is true. Inside this check
a:Arg is set to {argument}. Note that evaluated expression must
not echo any warnings using :echoerr: they will be captured by
:try and check will fail.
keyof Dictionary
Checks, whether {argument} is a key of {checkargument}. {argument}
must be of a type String.
hkey String
Checks, whether {argument} is a Dictionary and has key
{checkargument}.
equal a (everything)
Checks, whether {argument} is identical to {checkargument}.
var String (either empty or contains comma-delimited variable type
names: buffer, window, tabpage, global, vim, option, any)
Checks, whether {argument} is a variable name, this
variable exists and has specified type. (`option' variable names
must start with `&', others with `b:', `w:', `t:', `g:' or `v:'
for buffer, window, tabpage, global or vim responsively. See
internal-variables for details.)
any _ (argument is ignored)
Always true.
num (Fractional a) => Either (Either a String, a) (a)
(list with one or two elements)
Checks whether {argument} is a number (depending on a type of
first number in {checkargument} it must have a type either Integer
or any of Integer and Fload) from first element of {checkargument}
(if it is not equal to empty string) to the second element of
{checkargument} (if it exists).
Examples: >
Check Argument Result
["num", [0]] 1 True
["num", [0]] -1 False
["num", [0]] 1.0 False
["num", [0.0]] 1.0 True
["num", [0.0]] 1 True
["num", ["", 0]] 1 False
["num", ["", 0]] -1 True
["num", ["", 0]] -1.0 False
["num", [0, 2]] 0 True
["num", [0, 2]] 3 False
["num", [0, 2]] -1 False
["num", [0, 2.0]] 1.0 False
["num", [0.0, 2.0]] 1.0 True
["num", [0.0, 2]] 1.0 True
nums (see above) chk-check-nums
Just like chk-check-num, but before doing a check it runs
eval({argument}).
isreg _ (argument is ignored)
Check whether {argument} is a correct regular expression.
hlgroup _ (argument is ignored)
Check whether {argument} is a name of existing highlight group.
file String
Test, whether {argument} is a filename, which
{checkargument} Meaning
r exists and is readable;
rw exists and is writeable;
d exists and is a directory;
x exists and is executable;
dw exists, is a directory and is writeable;
w either exists and is writeable or does not
exist, but is in directory where we could
write.
len Either (Integer, Integer) (Integer) (list with one or two
integers)
Checks whether {argument} is a list with length from
{checkargument}[0] to {checkargument}[1] (or infinity if it is not
present). Use regular expressions to test for string length.
chklst [ Check ] (list of checks)
Checks whether {argument} is a list with length equal to length of
{checkargument} and every element in {argument} matches Check in
the identical position.
optlst ([ Check ], [ Check ]) (two lists of checks)
Checks whether {argument} is a list with length not less then
length of {checkargument}[0] and not greater then sum of
lengths of {checkargument}[0] and {checkargument}[1], first
len({checkargument}[0]) elements of {argument} match checks in
{checkargument}[0] and other elements of {argument} match checks
in {checkargument}[1].
alllst Check
Checks whether {argument} is a list and every element in
{argument} matches {checkargument}.
dict [(Check, Check)] (list of lists of two checks)
If {argument} is a dictionary then for every key of {argument} if
it matches left Check and value does not match right check return
False. Also return False if some key matches none of right checks.
map ({CheckName}, [ {CheckArgument} ])
For every {CheckArgument} in list {checkargument}[1] check whether
{argument} matches check [{CheckName}, {CheckArgument}].
allorno [ Check ] (list of checks)
Check succeeds either if {argument} matches all Checks in
{checkargument} or none of Checks in {checkargument}.
not Check
Check, whether {argument} does not match {checkargument}.
or [ Check ] (list of checks)
Check, whether {argument} matches any of checks in
{checkargument}.
and [ Check ] (list of checks)
Checks, whether {argument} matches all of checks in
{checkargument}.
-----------------------------------------------------------------------------
2.3. Models chk-model
{model} is a dictionary with required key "model" and some other keys, which
depend on "model".
Model Description
simple Required keys: "required" :: [ ArgTrans ] (list of transformations)
Meaning: there must be exactly len("required") arguments
in {arguments}, all must be successfully
transformed by appropriate ArgTrans.
Examples:
If we need to check arguments to the pow() function: >
pow(Float, Float) -> Float
{ "model": "simple",
"required": [["or", ["type", type(0.0)],
["type", type(0)]],
["or", ["type", type(0.0)],
["type", type(0)]]] }
<
optional Required keys: no
Optional keys: "required" :: [ ArgTrans ]
"optional" :: [(ArgTrans, ArgTrans, a)]
(list of lists of three elements: transformation
for present argument, transformation for default
value and default value)
"next" :: ArgTrans
Meaning: there must be at least len("required") arguments (or 0 if
it is not present) and at most len("optional") optional
arguments (unless "next" key is present). If some optional
argument is present it is transformed by first ArgTrans. If
it is not present, then third value in list is transformed
using the second ArgTrans. After all optional arguments
were processed, all other arguments are transformed using
ArgTrans from "next" key. If there is no "next" key and
number of arguments is greater then number of required plus
number of optional arguments, then 0 is returned,
indicating that an error occured.
Example:
If we need to check arguments to the matchstr() function: >
matchstr(String, Regex[, UInteger[, UInteger]])
{ "model": "optional",
"required": [["type", type("")],
["isreg", ""]],
"optional": [[["num", [0]], {}, 0],
[["num", [0]], {}, 0]] }
<
prefixed Required keys: no
Optional keys: "required" :: [ ArgTrans ]
"optional" :: [(ArgTrans, ArgTrans, a)]
"prefrequired" :: {prefix: ArgTrans}
(dictionary with values identical to
"required" values)
"prefoptional" :: {prefix: (ArgTrans,
ArgTrans, a)}
(dictionary with values identical to
"optional" values)
"preflist" :: [ String ] (list of
strings)
"allowtrun" :: Bool
"altpref" :: [ prefix ] (list of strings)
Meaning:
Command must look like that: >
Command [required_arguments]
\ [optional_arguments]
\ [{prefix} {argument}]
\ [{prefixFromPreflist} [arguments]]
<
Here [required_arguments] are described in "required" key and
are handled just like in chk-model-simple;
[optional_arguments] are described in "optional" key and are
handled just like in chk-model-optional, but with one
difference: [optional_arguments] must contain none of the keys
of "prefrequired" and "prefoptional" dictionaries. Then for all
keys from "prefrequired" and "prefoptional" not listed in
"preflist" if in the arguments list there is a sequence [{key},
{value}], then extend the last entry in arguments list (it will
always be a dictionary) with { {key}: {value} } pair. Prefixes
listed in "altpref" does not require any values, though they
make take one if they are present in "prefrequired" or
"prefoptional" as well, so if `prefix' is in "altpref" and in
"prefrequired", then either of `prefix' (=`prefix 1'),
`noprefix' (=`prefix 0', default) and `prefix {value}' are
possible. If some key from "prefrequired" or "prefoptional" is
listed in "preflist" then all arguments starting with one equal
to this key and ending with one of the keys from "prefrequired"
or "prefoptional" are added to the list. Last entry in arguments
list will be extended with { {key}: {list} } pair then. Key
"allowtrun" denies or allows (default: allow) reducing prefixes.
For example, if there are prefixes “columns”, “count” and
“print” then if reducing is allowed “columns” may be reduced to
“col”, “count” to “cou” and “print” to “p”. Presence of either
"optional" or "preflist" keys denies reducing.
Examples: >
{"model": "prefixed",
"required": [{}],
"optional": [[{}, {}, "def"]],
"prefrequired": {"for": {}, "in": {}},
"prefoptional": {"using": [{}, {}, "defU",
"list": [{}, {}, ["defL"]]},
"preflist": ["in", "list"]}
Cmdline => Result:
required optional for F in I using U list L =>
["required", "optional", {"for": "F",
"in": ["I"],
"using": "U",
"list": ["L"]}]
required for F in I using U list L =>
["required", "def", {"for": "F",
"in": ["I"],
"using": "U",
"list": ["L"]}]
required four for F in I using U list L =>
["required", "four", {"for": "F",
"in": ["I"],
"using": "U",
"list": ["L"]}]
required for F in I1 I2 =>
["required", "def", {"for": "F",
"in": ["I1", "I2"],
"using": "defU",
"list": ["defL"]}]
required for F in I1 I2 list L1 L2 =>
["required", "def", {"for": "F",
"in": ["I1", "I2"],
"using": "U",
"list": ["L1", "L2"]}]
<
actions Required keys: "actions" :: {action: Model}
Optional keys: "allowtrun" :: Bool
Meaning: first argument must be one of keys from "actions"
dictionary. Other arguments must be valid models. Key
"allowtrun" denies or allows (default: allow) reducing
action names. For example, if there are actions “start”,
“stop” and “restart” then if reducing is allowed “start”
may be reduced to “sta”, “stop” to “sto” and “restart” to
“r”.
aslist Required keys: "check" :: ArgTrans
Meaning: check argument list as a single argument
------------------------------------------------------------------------------
2.4. Transformations chk-trans
Every ArgTrans is either a dictionary or a Check. If it is a Check, then
argument is not transformed, only checked. If it is a dictionary it may
contain the following keys:
Key Value and description
check Check
Check the argument.
trans Transformation
Transform the argument using transformation. Every transformation is
a list of two elemnts: name of the transformation and argument.
Possible transformations:
Name {transargument}
eq a (any value)
Return 1 if {argument} is identical to {transargument} and
0 otherwise.
func Function (a -> b) (function that takes one argument)
Pass the argument to the function and use the result.
eval String (expression)
Eval the {transargument} and take the result. Inside the
expression a:Arg is {argument} and a:Trans is
{transargument}.
earg _ (argument is ignored)
Eval the being transformed argument and take the result. Note
that {transargument} is still available via a:Trans
variable.
call [{functionarguments}] (list of function arguments)
Take the result of call({argument}, {transargument}, {}).
pipe [ Transformation ] (list of transformations)
Take the result of n'th transformation and transform it using
the (n+1)'th transformation.
transchk Check
Check the result of transformation.
skip _ (value is ignored)
Do not add {argument} to the arguments list.
==============================================================================
3. Example usage chk-usage
Pretend that you want to create a function that will echo message with changed
highlighting and want to throw an exception if given higlight group does not
exist: >
" Tests, whether given highlight group exists
function HighlightExists(hlname)
try
silent execute "highlight ".a:name
return 1
catch
return 0
endtry
endfunction
" Get a dictionary with this plugins' functions
let s:chkdict=load#LoadFuncdict().getfunctions("chk")
function EchoHighlighted(hlname, text)
" Test, whether given ``hlname'' is a valid name for a highlight group
" and this highlight group exists.
if !s:chkdict.checkargument(["and", [["regex", '^[a-zA-Z0-9_]\+$', "Invalid name for highlight group"],
\["func", function("HighlightExists"), "Highlight group does not exist"]]],
\a:hlname)
throw "Invalid hlname."
endif
execute "echohl ".a:hlname
echo a:text
echohl None
endfunction
Now, if you do >
call EchoHighlighted("Comment", "This message will be highlighted like a comment")
you will get highlighted message, but these calls will throw an error: >
call EchoHighlighted("Invalid Name", "This will throw an error")
" output:
" chk/achk.regex:InvalidValue(Value does not match regular expression /'^[a-zA-Z0-9_]\+$'/: 'Invalid Name')
" chk/achk._main:InvalidValue(Invalid name for highlight group)
" chk/achk._main:InvalidValue(Invalid value)
" Error detected while processing function EchoHighlighted:
" line 6:
" E605: Exception not caught: Invalid hlname.
call EchoHighlighted("NonExistantGroup", "This will throw an error too")
" output:
" chk/achk.func:InvalidValue(Function function('HighlightExists') returned a error)
" chk/achk._main:InvalidValue(Highlight group does not exist)
" chk/achk._main:InvalidValue(Invalid value)
" Error detected while processing function EchoHighlighted:
" line 6:
" E605: Exception not caught: Invalid hlname.
Here is the same example, rewritten to use checkarguments function and new
`hlgroup' check: >
" Get a dictionary with this plugins' functions
let s:chkdict=load#LoadFuncdict().getfunctions("chk")
function EchoHighlighted(...)
" Test, whether given ``hlname'' is a valid name for a highlight group
" and this highlight group exists.
let args=s:chkdict.checkarguments({"model": "simple",
\"required": [["hlgroup", ""],
\["any", ""]],}
\a:000)
if type(args)!=type([])
throw "Invalid arguments."
endif
execute "echohl ".args[0]
echo args[1]
echohl None
endfunction
vim: ft=help:tw=78:nowrap