jak-project/common/repl/config.cpp
Tyler Wilding eb703ee96e
REPL related improvements and fixes (#3545)
Motivated by - https://github.com/open-goal/opengoal-vscode/pull/358

This addresses the following:
- Fixes #2939 spam edge-case
- Stop picking a different nREPL port based on the game mode by default,
this causes friction for tools in the average usecase (having a REPL
open for a single game, and wanting to connect to it). `goalc` spins up
fine even if the port is already bound to.
- For people that need/want this behaviour, adding per-game
configuration to the `repl-config.json` is on my todo list.
- Allows `goalc` to permit redefining symbols, including functions. This
is defaulted to off via the `repl-config.json` but it allows you to for
example, change the definition of a function without having to restart
and rebuild the entire game.
![Screenshot 2024-06-02
124558](https://github.com/open-goal/jak-project/assets/13153231/28f81f6e-b7b8-4172-9787-f96e4ab1305b)
- Updates the welcome message to include a bunch of useful metadata
up-front. Cleaned up all the startup logs that appear when starting
goalc, many of whom's information is now included in the welcome
message.
  - Before:

![image](https://github.com/open-goal/jak-project/assets/13153231/814c2374-4808-408e-9ed6-67114902a1d9)

  - After:
![Screenshot 2024-06-01
235954](https://github.com/open-goal/jak-project/assets/13153231/f3f459fb-2cbb-46ba-a90f-318243d4b3b3)
2024-06-03 00:14:52 -04:00

113 lines
3.5 KiB
C++

#include "config.h"
#include "common/versions/versions.h"
#include "fmt/core.h"
namespace REPL {
void to_json(json& j, const Config& obj) {
j = json{
{"nreplPort", obj.nrepl_port},
{"gameVersionFolder", obj.game_version_folder},
{"numConnectToTargetAttempts", obj.target_connect_attempts},
{"asmFileSearchDirs", obj.asm_file_search_dirs},
{"keybinds", obj.keybinds},
{"perGameHistory", obj.per_game_history},
{"permissiveRedefinitions", obj.permissive_redefinitions},
};
}
void from_json(const json& j, Config& obj) {
// TODO - make a camelCase variant of json_serialize/deserialize macros
if (j.contains("nreplPort")) {
j.at("nreplPort").get_to(obj.nrepl_port);
}
if (j.contains("gameVersionFolder")) {
j.at("gameVersionFolder").get_to(obj.game_version_folder);
}
if (j.contains("numConnectToTargetAttempts")) {
j.at("numConnectToTargetAttempts").get_to(obj.target_connect_attempts);
}
if (j.contains("asmFileSearchDirs")) {
j.at("asmFileSearchDirs").get_to(obj.asm_file_search_dirs);
}
if (j.contains("appendKeybinds")) {
j.at("appendKeybinds").get_to(obj.append_keybinds);
}
if (j.contains("keybinds")) {
std::vector<KeyBind> keybinds = j.at("keybinds");
if (!obj.append_keybinds) {
obj.keybinds = keybinds;
} else {
// append the keybinds
// - start with the provided ones
// - skip ones from the default set if they have the same key + modifier combination
for (const auto& default_bind : obj.keybinds) {
// check if it's a duplicate bind
bool duplicate = false;
for (const auto& new_bind : keybinds) {
if (new_bind.key == default_bind.key && new_bind.modifier == default_bind.modifier) {
duplicate = true;
break;
}
}
if (!duplicate) {
keybinds.push_back(default_bind);
}
}
obj.keybinds = keybinds;
}
}
if (j.contains("perGameHistory")) {
j.at("perGameHistory").get_to(obj.per_game_history);
}
if (j.contains("permissiveRedefinitions")) {
j.at("permissiveRedefinitions").get_to(obj.permissive_redefinitions);
}
// if there is game specific configuration, override any values we just set
if (j.contains(version_to_game_name(obj.game_version))) {
from_json(j.at(version_to_game_name(obj.game_version)), obj);
}
}
std::string KeyBind::string() const {
switch (modifier) {
case KeyBind::Modifier::CTRL:
return fmt::format("CTRL-{}", key);
case KeyBind::Modifier::SHIFT:
return fmt::format("SHIFT-{}", key);
case KeyBind::Modifier::META:
return fmt::format("META-{}", key);
}
}
void to_json(json& j, const KeyBind& obj) {
j = json{{"description", obj.description}, {"command", obj.command}, {"key", obj.key}};
switch (obj.modifier) {
case KeyBind::Modifier::CTRL:
j["modifier"] = "ctrl";
break;
case KeyBind::Modifier::SHIFT:
j["modifier"] = "shift";
break;
case KeyBind::Modifier::META:
j["modifier"] = "meta";
break;
}
}
void from_json(const json& j, KeyBind& obj) {
j.at("description").get_to(obj.description);
j.at("command").get_to(obj.command);
j.at("key").get_to(obj.key);
auto modString = j.at("modifier").get<std::string>();
if (modString == "ctrl") {
obj.modifier = KeyBind::Modifier::CTRL;
} else if (modString == "shift") {
obj.modifier = KeyBind::Modifier::SHIFT;
} else if (modString == "meta") {
obj.modifier = KeyBind::Modifier::META;
}
}
} // namespace REPL