initial commit
This commit is contained in:
commit
29bb03ffe1
6 changed files with 297 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
build/
|
||||||
|
recovery/
|
||||||
|
BeefSpace_User.toml
|
6
BeefProj.toml
Normal file
6
BeefProj.toml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
FileVersion = 1
|
||||||
|
|
||||||
|
[Project]
|
||||||
|
Name = "LybCL"
|
||||||
|
TargetType = "BeefLib"
|
||||||
|
StartupObject = "LybCL.Program"
|
2
BeefSpace.toml
Normal file
2
BeefSpace.toml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
FileVersion = 1
|
||||||
|
Projects = {LybCL = {Path = "."}}
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 Jannis vH
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
11
README.md
Normal file
11
README.md
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
## LybCL
|
||||||
|
A simpleish commandline parsing library with automatic routing functionality
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
Clone the repository and add it to your beef workspace as you usually would.
|
||||||
|
This libary is also single file, so you may also just copy the file directly into your project if necessary
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
The .bf sourcefile contains all information neccessary to use the library.
|
||||||
|
You basically just create a new LybCl object by inserting the args[] and then call function on that object.
|
||||||
|
The CMDRouter attribute can be used for the automatic routing functionality, however you will need to ensure the type is refelcted.
|
254
src/LybCl.bf
Normal file
254
src/LybCl.bf
Normal file
|
@ -0,0 +1,254 @@
|
||||||
|
/*
|
||||||
|
[LybCL]
|
||||||
|
Lyb Commandline library/tool
|
||||||
|
Parses the String[] that a program starts with and allows the user to use the arguments easier
|
||||||
|
Made by Booklordofthedings
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
Everything starts by creating a commandline object and by passing in the String[]
|
||||||
|
LybCl handles everything else and you only need to make sure to correctly dispose of it.
|
||||||
|
|
||||||
|
GetArgs(int) returns the value of the args by index, if it exists. Otherwise it returns an empty stringview
|
||||||
|
GetCommand() returns the command thats to be executed: ./Programname.exe {command} -parameters
|
||||||
|
HasFlag(params StringView) checks wether a given flag is set as a value. returns a boolean
|
||||||
|
GetParameter(params StringView) checks the value of a given parameter. Returns an empty string if its not found.
|
||||||
|
RouteReturnCode{get;set} allows you to set the return value of the Route() call. only use inside one of the marked methods
|
||||||
|
Route() Does reflection and calls functions that match the given route
|
||||||
|
-Use CMDRouterAttriíbute on a static function to mark it as a routeable functions
|
||||||
|
-The first attribute needs to be a LybCl type
|
||||||
|
-Any other parameter needs to have be nullable (Type?) and have a Parse(StringView) function that returns a Result<T>
|
||||||
|
-the route is made out of literals divided by spaces, while the required variables are to be included inside of curly brackets
|
||||||
|
"generate new {a}" <- this route executes, if the user calls Program.exe generate new {any}. any being any value that will be parsed and inserted into the route
|
||||||
|
|
||||||
|
Parameter design:
|
||||||
|
[ProgramName] [Command] [Subcommand] [Parameter] [Arguments/Flags]
|
||||||
|
[ProgramName] name of the program/exectuteable to run (test.exe/git)
|
||||||
|
[Command]/[Subcommands] indicates the route or specific functionality to be executed. may be only one command (install) or multiple (get install) or any other lenght
|
||||||
|
[Parameter] variable values that a command needs, like a filepath or url
|
||||||
|
[Arguments/Flags] contain additional information that is not required but may change how the command executes. flags are only boolean while arguments have to contain
|
||||||
|
an example call would be something like this
|
||||||
|
|
||||||
|
./Program.exe repository generate "https://github.com/booklordofthedings/repo" --verbose --logfile log.txt
|
||||||
|
|
||||||
|
|
||||||
|
some programs support arguments between the program name and command, however this tool does not
|
||||||
|
if you want to do global settings that apply to every command you can simply put them at the end of the command
|
||||||
|
and just read them in before doing any processing or routing, to set them
|
||||||
|
*/
|
||||||
|
namespace LybCL;
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Collections;
|
||||||
|
class LybCl
|
||||||
|
{
|
||||||
|
private String[] _args;
|
||||||
|
private Dictionary<String, String> _parameters = new .() ~ DeleteDictionaryAndKeysAndValues!(_);
|
||||||
|
private CMDRouterAttribute _attributeInfo;
|
||||||
|
|
||||||
|
public this(String[] pArgs)
|
||||||
|
{
|
||||||
|
_args = pArgs;
|
||||||
|
for(int i < _args.Count)
|
||||||
|
{
|
||||||
|
if(!_args[i].StartsWith('-'))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int endIndex = -1;
|
||||||
|
for(int j < _args[i].Length)
|
||||||
|
{
|
||||||
|
if(_args[i][j] != '-')
|
||||||
|
{
|
||||||
|
endIndex = j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(endIndex < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
StringView name = .(_args[i],endIndex);
|
||||||
|
|
||||||
|
if(!(i+1 < _args.Count) || _args[i+1].StartsWith('-'))
|
||||||
|
{
|
||||||
|
_parameters.Add(new .(name), new .(""));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
_parameters.Add(new .(name), new .(_args[i+1]));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Allows users to set what the call for route will return
|
||||||
|
public int RouteReturnCode { get; set; } = 0;
|
||||||
|
|
||||||
|
public int Count
|
||||||
|
{
|
||||||
|
public get {
|
||||||
|
return _args.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///Get the raw argument at the given index or an empty string
|
||||||
|
public StringView GetArgs(int pIndex)
|
||||||
|
{
|
||||||
|
if(pIndex < 0 || !(pIndex < _args.Count))
|
||||||
|
return "";
|
||||||
|
else
|
||||||
|
return _args[pIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
///Get the command or an empty string
|
||||||
|
public StringView GetCommand()
|
||||||
|
{
|
||||||
|
if(_args.Count < 1)
|
||||||
|
return "";
|
||||||
|
else if(!_args[0].StartsWith('-'))
|
||||||
|
return _args[0];
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
///Get wether a specific flag is set, allows aliases
|
||||||
|
public bool HasFlag(params Span<StringView> pArgs)
|
||||||
|
{
|
||||||
|
for(var arg in pArgs)
|
||||||
|
{
|
||||||
|
if(!_parameters.ContainsKey(scope .(arg)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(_parameters[scope .(arg)] == "")
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
///Gets the value of a argument and returns empty if not found
|
||||||
|
public StringView GetParameter(params Span<StringView> pArgs)
|
||||||
|
{
|
||||||
|
for(var arg in pArgs)
|
||||||
|
{
|
||||||
|
if(!_parameters.ContainsKey(scope .(arg)))
|
||||||
|
continue;
|
||||||
|
return _parameters[scope .(arg)];
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
///Process all of the reflected and routed methods and tries to find one that matches, then it calls it
|
||||||
|
public void Route()
|
||||||
|
{
|
||||||
|
for(let type in Type.Types)
|
||||||
|
{
|
||||||
|
m: for(let method in type.GetMethods())
|
||||||
|
{
|
||||||
|
let attributeInfo = method.GetCustomAttribute<CMDRouterAttribute>();
|
||||||
|
if(attributeInfo case .Err)
|
||||||
|
continue;
|
||||||
|
_attributeInfo = attributeInfo.Value;
|
||||||
|
//Ensure that the route works
|
||||||
|
var routingList = scope List<StringView>();
|
||||||
|
attributeInfo.Value.GetRouteList(routingList);
|
||||||
|
r: for(int i < routingList.Count)
|
||||||
|
{
|
||||||
|
if(!(i < _args.Count))
|
||||||
|
continue m;
|
||||||
|
|
||||||
|
if(routingList[i].StartsWith('{') && routingList[i].EndsWith('}'))
|
||||||
|
continue r;
|
||||||
|
|
||||||
|
if(routingList[i] != _args[i])
|
||||||
|
continue m;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object[] args = scope Object[method.ParamCount];
|
||||||
|
for(int i = 0; i < method.ParamCount; i++)
|
||||||
|
{
|
||||||
|
if(i == 0)
|
||||||
|
{
|
||||||
|
args[i] = this;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for(var fd in method.GetParamType(i).GetMethods())
|
||||||
|
{
|
||||||
|
Console.WriteLine(fd.Name);
|
||||||
|
}
|
||||||
|
args[i] = null;
|
||||||
|
}
|
||||||
|
var res = method.Invoke(null, params args);
|
||||||
|
res.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringView GetValue(StringView pVal)
|
||||||
|
{
|
||||||
|
var route = scope List<StringView>();
|
||||||
|
_attributeInfo.GetRouteList(route);
|
||||||
|
for(int i < route.Count)
|
||||||
|
{
|
||||||
|
if(route[i] == scope $"\{{pVal}\}")
|
||||||
|
{
|
||||||
|
if(i < _args.Count)
|
||||||
|
return _args[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(.Method, .AlwaysIncludeTarget | .ReflectAttribute, ReflectUser=.All), AlwaysInclude]
|
||||||
|
struct CMDRouterAttribute : Attribute, IOnMethodInit
|
||||||
|
{
|
||||||
|
private String _route;
|
||||||
|
public this(String pRoute)
|
||||||
|
{
|
||||||
|
_route = pRoute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetRouteList(List<StringView> pBuffer)
|
||||||
|
{
|
||||||
|
var seperationChars = scope char8[](' ','\t');
|
||||||
|
var enumerator = _route.Split(seperationChars,.RemoveEmptyEntries);
|
||||||
|
for(let entry in enumerator)
|
||||||
|
pBuffer.Add(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Comptime]
|
||||||
|
public void OnMethodInit(MethodInfo methodInfo, Self* prev)
|
||||||
|
{
|
||||||
|
|
||||||
|
String toAppend = scope .();
|
||||||
|
for(int i = 1; i < methodInfo.ParamCount; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
//Remove nullable
|
||||||
|
var t = methodInfo.GetParamType(i) as SpecializedGenericType;
|
||||||
|
|
||||||
|
toAppend.Append(scope $"""
|
||||||
|
var {methodInfo.GetParamName(i)};
|
||||||
|
let parseResult{methodInfo.GetParamName(i)} = {t.GetGenericArg(0).GetFullName(.. scope .())}.Parse(cl.GetValue("{methodInfo.GetParamName(i)}"));
|
||||||
|
if(parseResult{methodInfo.GetParamName(i)} case .Err)
|
||||||
|
return;
|
||||||
|
{methodInfo.GetParamName(i)} = ({methodInfo.GetParamType(i)})parseResult{methodInfo.GetParamName(i)}.Value;
|
||||||
|
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
Compiler.EmitMethodEntry(methodInfo, toAppend);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Here are the types that dont have a
|
||||||
|
*/
|
||||||
|
namespace System
|
||||||
|
{
|
||||||
|
extension StringView
|
||||||
|
{
|
||||||
|
public static Result<StringView> Parse(StringView pInput)
|
||||||
|
{
|
||||||
|
return .Ok(pInput);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue