-rw-r--r--.gitignore2
-rw-r--r--Main.gd10
-rw-r--r--Main.tscn6
-rw-r--r--README.md3
-rw-r--r--addons/gdcli/Arg.gd64
-rw-r--r--addons/gdcli/Parser.gd72
-rw-r--r--project.godot34
7 files changed, 191 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..dabd852
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.vscode/
+.import/
diff --git a/Main.gd b/Main.gd
new file mode 100644
index 0000000..f635083
--- /dev/null
+++ b/Main.gd
@@ -0,0 +1,10 @@
+extends Node
+
+
+func _ready():
+ var p = Parser.new()
+ p.add_argument(Arg.new({triggers = ["-fly", "--fley"], n_args = 2, help = "i eat donkeys"}))
+ p.add_argument(Arg.new({triggers = ["-bard", "--flgersog"], n_args = 2, help = "me 4"}))
+ p.add_argument(Arg.new({triggers = ["--radiation"], n_args = "*", help = "i am radiation"}))
+ print(p.parse_arguments())
+ print(p.help())
diff --git a/Main.tscn b/Main.tscn
new file mode 100644
index 0000000..cc043c2
--- /dev/null
+++ b/Main.tscn
@@ -0,0 +1,6 @@
+[gd_scene load_steps=2 format=2]
+
+[ext_resource path="res://Main.gd" type="Script" id=1]
+
+[node name="Main" type="Node2D"]
+script = ExtResource( 1 )
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..298332e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+# godot cli parser
+
+waiting on [godot-proposals/4815](https://github.com/godotengine/godot-proposals/issues/4815) for the full experience.
diff --git a/addons/gdcli/Arg.gd b/addons/gdcli/Arg.gd
new file mode 100644
index 0000000..828bbf1
--- /dev/null
+++ b/addons/gdcli/Arg.gd
@@ -0,0 +1,64 @@
+extends Reference
+class_name Arg
+
+var n_args := 0
+var arg_type := "" # can be *
+var triggers: PoolStringArray = []
+var help := ""
+var arg_names := ""
+var dest := ""
+var default = ""
+
+
+func find_trigger(to_find: String) -> String:
+ for t in triggers:
+ if t == to_find:
+ return t
+ return ""
+
+
+func _init(
+ options := {triggers = [], n_args = 0, help = "", dest = "", default = "", arg_names = ""}
+) -> void:
+ help = opt_get(options, "help", "")
+ triggers = opt_get(options, "triggers", [])
+ if typeof(opt_get(options, "n_args", 0)) == TYPE_STRING:
+ arg_type = opt_get(options, "n_args", "")
+ else:
+ n_args = opt_get(options, "n_args", 0)
+ dest = opt_get(options, "dest", dest_name())
+ default = opt_get(options, "default", "")
+ arg_names = opt_get(options, "arg_namaes", get_arg_names())
+
+
+func opt_get(opt: Dictionary, key: String, df):
+ return opt[key] if key in opt else df
+
+
+func add_trigger(t: String) -> void:
+ triggers.append(t)
+
+
+func get_arg_names():
+ var r_names := "["
+ if not arg_type:
+ for i in n_args:
+ r_names += " arg%s " % i
+ else:
+ r_names += " ..."
+ return r_names + "]"
+
+
+func small_arg() -> String:
+ var small := ""
+ for t in triggers:
+ small = t if len(t) < len(small) or !small else small
+ return small
+
+
+func dest_name() -> String:
+ return small_arg().replace("-", "")
+
+
+func format_triggers() -> String:
+ return triggers.join(", ") + " " + arg_names
diff --git a/addons/gdcli/Parser.gd b/addons/gdcli/Parser.gd
new file mode 100644
index 0000000..d618a0f
--- /dev/null
+++ b/addons/gdcli/Parser.gd
@@ -0,0 +1,72 @@
+extends Reference
+class_name Parser
+
+var target_args := []
+
+
+func add_argument(arg: Arg):
+ target_args.append(arg)
+
+
+func parse_arguments():
+ var cmdline_args = Array(OS.get_cmdline_args())
+ var args := {unhandled = []}
+ var i := -1
+ var star: String
+ while i < len(cmdline_args) - 1:
+ i += 1
+ var res := __search_target_args(cmdline_args[i])
+ if res:
+ if res.n_args:
+ args[res.dest] = cmdline_args.slice(i + 1, i + res.n_args)
+ i += res.n_args
+ star = ""
+ else:
+ match res.arg_type:
+ "*":
+ star = res.dest
+ args[res.dest] = cmdline_args.slice(i + 1, i)
+ else:
+ if star:
+ args[star].append(cmdline_args[i])
+ breakpoint
+ else:
+ args.unhandled.append(cmdline_args[i])
+ for r in target_args:
+ if not r.dest in args:
+ args[r.dest] = r.default
+ return args
+
+
+func __search_target_args(to_find: String) -> Arg:
+ for arg in target_args:
+ if arg.find_trigger(to_find):
+ return arg
+ return null
+
+
+func help() -> String:
+ var size = 1
+ for arg in target_args: # find the longest arguments
+ size = len(arg.format_triggers()) if len(arg.format_triggers()) > size else size
+
+ var options := ""
+ var usage := "godot "
+ for arg in target_args:
+ usage += "[%s] " % arg.small_arg()
+ options += arg.format_triggers() + " "
+
+ for _i in range(size - len(arg.format_triggers())):
+ options += " "
+ options += arg.help + "\n"
+ var help = """
+usage: {usage}
+
+{description}
+
+options:
+{options}
+""".format(
+ {usage = usage, description = "", options = options.indent(" ")}
+ )
+ return help
diff --git a/project.godot b/project.godot
new file mode 100644
index 0000000..4f9b632
--- /dev/null
+++ b/project.godot
@@ -0,0 +1,34 @@
+; Engine configuration file.
+; It's best edited using the editor UI and not directly,
+; since the parameters that go here are not all obvious.
+;
+; Format:
+; [section] ; section goes between []
+; param=value ; assign values to parameters
+
+config_version=4
+
+_global_script_classes=[ {
+"base": "Reference",
+"class": "Arg",
+"language": "GDScript",
+"path": "res://addons/Arg.gd"
+}, {
+"base": "Reference",
+"class": "Parser",
+"language": "GDScript",
+"path": "res://addons/Parser.gd"
+} ]
+_global_script_class_icons={
+"Arg": "",
+"Parser": ""
+}
+
+[application]
+
+config/name="gdcli"
+run/main_scene="res://Main.tscn"
+
+[editor]
+
+main_run_args=" --radiation rad crad -bard rofl"