Open user menu
Files
testCLI.src
Mycli = {}
Mycli = {}
Mycli.name = "mycli"
Mycli.commands = {}
// args ending with * are required
// options ending with = require a value to be passed after the option
Mycli.commands.hello_sig = {}
Mycli.commands.hello_sig["description"] = "it says hello to you"
Mycli.commands.hello_sig["args"] = [{ "name*": "first name"}, { "second_name": "second name (optional)"} ]
Mycli.commands.hello_sig["args"] = ["name*", "second_name"]
Mycli.commands.hello_sig["options"] = [{["-c", "--capitalize"]: "will capitalize your name"}, {["-f=", "--from="]: "name from the person saying hello"}]
// options that are not passed will be set to null, also if they are passed all the keys will be set to the options value
// if the functions is called with --help or -h then it wont be called and the documentation will be printed istead
Mycli.commands.hello = function(args = [], options = {})
if options["-c"] then
name = name.values[0]
name[0].upper
name = name.join("")
end if
print(["hello", name, second_name].join(" "))
end function
Mycli.main_sig = {}
Mycli.main_sig["description"] = "shit cli script"
//required args should come first than optional ones
Mycli.main_sig["args"] = [{ ["commands*", Mycli.commands]: "Accepted commands: "}, {"email": "your email why not"} ]
Mycli.main_sig["args"] = ["email*", ["commands*", Mycli.commands]]
Mycli.main_sig["options"] = [{"-d": "dez"}, {["-c", "--capitalize"]: "will capitalize your name"}, {["-f=", "--from="]: "name from the person saying hello"}]
// the main fuction is the root function of the cli script
// this function will allways be called if the the required args are passed(and they are valid)
// so in this case bc we have another class as args this function will be called first
// then the matching command will be called after
Mycli.main = function(args = [], options = {})
globals["email"] = email
end function
// functions starting with __ wont trigger the main function
Mycli.__version = function()
print("0.0.1")
end function
import_code("/home/me/thor/libs/listLib.src") //requires on listlib
import_code("/home/me/thor/libs/thor.src") //requires on listlib
Thor.init(Mycli)
libs/thor.src
Thor = {}
Thor.init = function(class, root = true)
self.class = null
self.main = null
self.__commands = {}
self.commands = {}
self.root = root
if class.hasIndex("name") then self.name = class.name
self.class = class
if self.class.hasIndex("main") then self.main = self.to_command("main")
for obj in self.class
if typeof(obj["value"]) == "function" then
if obj["key"][:2] == "__" then
self.__commands[obj["key"]] = self.to_command(obj["key"])
else if obj["key"] != "main" then
self.commands[obj["key"]] = self.to_command(obj["key"])
end if
end if
end for
//print(self.main)
//print(self.__commands)
//print(self.commands)
if self.root == true then self.eval_command(self.main, params)
end function
// it takes a function name then returns an object with name, func key by default
// the description, options, [[required_args, optional args], [required_commands, optinal_commands]](if args is set) key is optional,
Thor.to_command = function(name)
command = {}
command["name"] = name
command["func"] = self.class[name]
if self.class.hasIndex(name + "_sig") then
sig = self.class[name + "_sig"]
else
return command
end if
if sig.hasIndex("description") then command["description"] = sig["description"]
arg_to_map = function(obj)
param = {}
if typeof(obj) == "list" then param["name"] = obj[0]
param["name"] = obj
//param["name"] = obj.indexes[0]
//param["description"] = obj[obj.indexes[0]]
return param
end function
option_to_map = function(obj)
param = {}
param["name"] = obj.indexes[0]
param["description"] = obj[obj.indexes[0]]
return param
end function
if sig.hasIndex("args") then
sig["args"] = Lst.map(sig["args"], @arg_to_map)
required = function(obj)
return obj.name[-1:] == "*"
end function
command["args"] = sig["args"]
command["required_args"] = Lst.select(sig["args"], @required)
command["optional_args"] = Lst.reject(sig["args"], @required)
f = function(obj)
return typeof(obj.name) == "list" and obj.name.len == 2 and typeof(obj.name[1]) == "map"
end function
commands = Lst.select(sig["args"], @f)
required = function(obj)
return obj.name[0][-1:] == "*"
end function
command["required_commands"] = Lst.select(commands, @required)
command["optional_commands"] = Lst.reject(commands, @required)
f = function(obj)
sub_cli = new Thor
sub_cli.init(obj["name"][1], false)
obj["commands"] = sub_cli
obj["name"] = obj["name"][0]
return obj
end function
command["required_commands"] = Lst.map(command["required_commands"], @f)
command["optional_commands"] = Lst.map(command["optional_commands"], @f)
end if
if sig.hasIndex("options") then
sig["options"] = Lst.map(sig["options"], @arg _to_map)
sig["options"] = Lst.map(sig["options"], @option _to_map)
command["options"] = sig["options"]
end if
return command
end function
Thor.has _command = function(command_name )
return self. commands.hasIndex( command_name) != 0
Thor.arg_allowed _commands = function(arg )
r = []
for i in arg[" commands"]. commands
r.push(i["key"])
end for
return r
end function
Thor.commands_list = function()
out = self.commands_doc_header
f = function(t)
return [t[0], t[1]["description"] ]
end function
commands_descs = Lst.map(Lst.to_list(self. commands, true), @f)
for desc in commands_descs
out = out + "<b> " + desc[0 ] + "</b> : " + desc[1]
Thor.command_help = function(command )
out = char(10)
if self.root == true then
out = out + self.name
else
out = out + command["name" ]
end if
out = out + " "
it_has_ commands = false
for arg in command["args"]
if arg.hasIndex("commands") then
out = out + "[" + arg["name"] + "] "
it_has_ commands = true
else
out = out + "<" + arg["name" ] + "> "
end if
end for
return out
end func tion
if command.hasIndex("options") then
out = out + char(10) + char(10)
out = out + "list of flags" + char(10)
for option in command.options
n = option.name
if typeof(option.name) == "list" then n = option.name.join(" ")
out = out + "<b>" + n + "</b> : " + option.description
if command.op tions.indexOf(option) < command.options.len - 1 then out = out + char(10)
end for
end if
Thor. command_help = function( command)
print( command["name"])
if it_has_ commands then
out = out + char(10)
for arg in command["args"]
if arg.hasIndex(" commands") then
out = out + char(10)
out = out + "list of valid commands for [" + arg ["name"] + "]" + char(10)
for command in arg["commands"].commands
out = out + "<b>" + command.value.name + "</b> : " + command.value.description + char(10)
end for
end if
end for
end if
print(out )
end function
// returns a list with [args, options] with args beign a list and options a map
// if -h or --help is passed it will ignore all the -- and - options and return options with -h and --help set
// if a options is passed and it is not defined on the command options sig then it will exit
// if a value options is passed with no value like -f= then it will exit
Thor.parse_params = function(command, params)
// filter for args
f = function(p)
return p[0] == "-"
end function
args = Lst.reject(params, @f)
options = {}
if command.hasIndex("options") then
//command map
c_all_options = null
c_options = []
c_value_options = []
f = function(obj)
return obj["name"]
end function
c_all_options = Lst.map(command["options"], @f)
has_value = function(obj)
if typeof(obj) == "list" then
return obj[0].indexOf("=") != null
else
return obj.indexOf("=") != null
end if
end function
c_options = Lst.reject(c_all_options, @has_value)
c_value_options = Lst.select(c_all_options, @has_value)
// param map
f = function(param)
return param[:1] == "-" and param.indexOf("=") == null
end function
params_options = Lst.select(params, @f)
f = function(param)
if param[:2] != "--" and param.len > 2 then
r = []
for i in param[1:].values
r.push("-" + i)
end for
return r
else
return param
end if
end function
params_options = Lst.uniq(Lst.flat(Lst.map(params_options, @f)))
f = function(param)
return param[:1] == "-" and param.indexOf("=") != null
end function
params_value_options = Lst.select(params, @f)
//print(c_all_options)
//print(c_options)
//print(c_value_options)
//print(params_options)
//print(params_value_options)
// check for errors
// check if undefined options was passed
f = function(p)
return p[:p.indexOf("=") + 1]
end function
vo_without_value = Lst.map(params_value_options, @f)
all_options = vo_without_value + params_options
for i in all_options
if Lst.flat(c_all_options).indexOf(i) == null then
if i == "-h" or i == "--help" then
return [args, {"-h": true, "--help": true}]
else
exit("option " + i + " is not defined, check the manual")
end if
end if
end for
// check if value options was passed without values
for i in params_value_options
if i[i.indexOf("=")+1:] == null then
exit("option " + i + " requires a value")
end if
end for
// set options to be passed for the command
c_options_by_key = {}
f = function(obj)
if typeof(obj) == "list" then
for i in obj
c_options_by_key[i] = obj
end for
else
c_options_by_key[obj] = [obj]
end if
end function
Lst.each(c_all_options, @f)
for i in params_options
for j in c_options_by_key[i]
options[j] = true
end for
end for
for i in params_value_options
value = i[i.indexOf("=")+1:]
key = i[:i.indexOf("=")+1]
for j in c_options_by_key[key]
options[j[:-1]] = value
end for
end for
for i in Lst.flat(c_all_options)
if i.indexOf("=") then
key = i[:-1]
else
key = i
end if
if options.hasIndex(key) == false then
options[key] = null
end if
end for
end if
return [args, options]
end function
Thor.eval_command = function(command, params)
p = self.parse_params(command, params)
args = p[0]
options = p[1]
if options.hasIndex("--help") or options.hasIndex("-h") then
self.command_help(command)
return
end if
if command.hasIndex("required_args") and command.hasIndex("required_commands") then
required_args_size = command["required_commands"].len + command["required_args"].len
if args.len < required_args_size then
self.command_help(command)
return
end if
end if
f = function(obj)
return obj["commands"]
end function
cs = Lst.map(command["required_commands"] + command["optional_commands"], @f)
f = function(obj)
return obj.commands
end function
cs = Lst.map(cs, @f)
f = function(obj)
return obj.indexes[0]
end function
cs = Lst.map(cs, @f)
valid_commands = cs
print(valid_commands)
print(args)
f = function(obj)
if obj.hasIndex("commands") then
return [] // todo
return Thor.arg_allowed_commands(obj)
else
return "*"
end if
end function
accepted_args = Lst.map(command["args"], @f)
print (accepted_args)
for i in args.indexes
if accepted_args.hasIndex(i) == false then break
if typeof (accepted_args[i]) == "list" and accepted_args[i].indexOf(args[i]) == null then
exit(args[i] + " is not a valid command, please check the docs.")
end if
end for
// push nulls to args until it is the same len ans the optional + required args len
i = 0
while i < accepted_args.len - args.len
args.push(null)
i = i + 1
end while
// TODO exec shit here
print(args)
//print(accepted_args)
end function