aboutsummaryrefslogtreecommitdiff
path: root/client/system/cli.gd
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-09-16 22:28:24 +0200
committermetamuffin <metamuffin@disroot.org>2025-09-16 22:28:24 +0200
commit3f98582f903e579d9f47aba48f3976345eabe123 (patch)
tree5124f087056171ccf0196169a4b3c4e992183fa3 /client/system/cli.gd
parente86637eade79ed5fef5ca2e9c169f5c40a314400 (diff)
downloadhurrycurry-3f98582f903e579d9f47aba48f3976345eabe123.tar
hurrycurry-3f98582f903e579d9f47aba48f3976345eabe123.tar.bz2
hurrycurry-3f98582f903e579d9f47aba48f3976345eabe123.tar.zst
Move some scripts to new "system" dir, add argument parser
Diffstat (limited to 'client/system/cli.gd')
-rw-r--r--client/system/cli.gd112
1 files changed, 112 insertions, 0 deletions
diff --git a/client/system/cli.gd b/client/system/cli.gd
new file mode 100644
index 00000000..b6ba8eef
--- /dev/null
+++ b/client/system/cli.gd
@@ -0,0 +1,112 @@
+# Hurry Curry! - a game about cooking
+# Copyright (C) 2025 Hurry Curry! contributors
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, version 3 of the License only.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+extends Node
+class_name Cli
+
+enum Mode { FLAG, OPTION, MULTI_OPTION, POSITIONAL }
+class Option:
+ var short #: String?
+ var long: String
+ var mode: Mode
+ var help: String
+ func _init(s, l: String, m: Mode, h: String):
+ short = s; long = l; mode = m; help = h
+
+static var OPTIONS := [
+ Option.new("h", "help", Mode.FLAG, "Show help"),
+ Option.new("s", "setting", Mode.MULTI_OPTION, "Per-launch setting override"),
+ Option.new(null, "connect_address", Mode.POSITIONAL, "Connect to a server directly without menu interaction")
+]
+
+static var opts = {} #: Dictionary[String, Variant]
+
+static func init() -> bool:
+ if not parse(): return false
+ if opts.has("help"):
+ print_help()
+ return false
+ return true
+
+static func print_help():
+ print("OPTIONS:\n")
+ for opt in OPTIONS:
+ var line = ""
+ if opt.mode == Mode.POSITIONAL:
+ line += "<" + opt.long.to_upper() + ">"
+ else:
+ if opt.short: line += "-" + opt.short + ", "
+ line += "--" + opt.long
+ if opt.mode == Mode.OPTION or opt.mode == Mode.MULTI_OPTION:
+ line += " <VALUE>"
+ while line.length() < 25: line += " "
+ line += " " + opt.help
+ print(line)
+
+static func parse() -> bool:
+ var args := OS.get_cmdline_user_args()
+ while not args.is_empty():
+ var arg := args[0]
+ args.remove_at(0)
+ if arg.begins_with("--"):
+ var long = arg.trim_prefix("--")
+ var opt_index = OPTIONS.find_custom(func(x): return x.long == long)
+ if opt_index == -1:
+ push_error("unknown long option \"%s\"" % long)
+ return false
+ if not _parse_opt(args, OPTIONS[opt_index]): return false
+ elif arg.begins_with("-"):
+ for short in arg.trim_prefix("-"):
+ var opt_index = OPTIONS.find_custom(func(x): return x.short == short)
+ if opt_index == -1:
+ push_error("unknown short option \"%s\"" % short)
+ return false
+ if not _parse_opt(args, OPTIONS[opt_index]): return false
+ else:
+ var opt_index = OPTIONS.find_custom(func(x): return x.mode == Mode.POSITIONAL)
+ if opt_index == -1:
+ push_error("no positional arguments")
+ return false
+ var opt = OPTIONS[opt_index]
+ opts[opt.long] = arg
+
+ print("Parsed options: ", opts)
+ return true
+
+static func _parse_opt(args: Array[String], opt: Option) -> bool:
+ match opt.mode:
+ Mode.FLAG:
+ opts[opt.long] = true
+ return true
+ Mode.OPTION:
+ if args.is_empty():
+ push_error("missing option value")
+ return false
+ opts[opt.long] = args[0]
+ args.remove_at(0)
+ return true
+ Mode.MULTI_OPTION:
+ if args.is_empty():
+ push_error("missing option value")
+ return false
+ if not opts.has(opt.long): opts[opt.long] = []
+ opts[opt.long].push_back(args[0])
+ args.remove_at(0)
+ return true
+ Mode.POSITIONAL:
+ push_error("positional arg doesnt need flag")
+ return false
+ push_error("unreachable")
+ return false