Compare commits
1 Commits
main
...
e93b046489
| Author | SHA1 | Date | |
|---|---|---|---|
| e93b046489 |
@@ -6,6 +6,7 @@
|
|||||||
#include <sophia/asset_registry.hpp>
|
#include <sophia/asset_registry.hpp>
|
||||||
#include <sophia/camera_2d.hpp>
|
#include <sophia/camera_2d.hpp>
|
||||||
#include <sophia/canvas.hpp>
|
#include <sophia/canvas.hpp>
|
||||||
|
#include <sophia/console/console_command_registry.hpp>
|
||||||
#include <sophia/frame_info.hpp>
|
#include <sophia/frame_info.hpp>
|
||||||
#include <sophia/types.hpp>
|
#include <sophia/types.hpp>
|
||||||
#include <sophia/ui/debug_ui.hpp>
|
#include <sophia/ui/debug_ui.hpp>
|
||||||
@@ -52,6 +53,8 @@ class Application {
|
|||||||
Camera2D camera;
|
Camera2D camera;
|
||||||
std::vector<std::string> args;
|
std::vector<std::string> args;
|
||||||
|
|
||||||
|
ConsoleCommandRegistry consoleCommandRegistry;
|
||||||
|
|
||||||
void drawMesh(MeshHandle handle, const glm::mat4& transform);
|
void drawMesh(MeshHandle handle, const glm::mat4& transform);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace sophia {
|
||||||
|
|
||||||
|
class ConsoleCommandRegistry {
|
||||||
|
public:
|
||||||
|
using Handler = std::function<std::string(const std::vector<std::string>&)>;
|
||||||
|
|
||||||
|
struct CommandInfo {
|
||||||
|
std::string name;
|
||||||
|
std::string help;
|
||||||
|
};
|
||||||
|
|
||||||
|
void registerCommand(std::string name, std::string help, Handler handler);
|
||||||
|
|
||||||
|
bool dispatch(const std::string& name, const std::vector<std::string>& args,
|
||||||
|
std::string& outResult) const;
|
||||||
|
|
||||||
|
std::vector<CommandInfo> list() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Command {
|
||||||
|
std::string help;
|
||||||
|
Handler handler;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::map<std::string, Command> commands;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sophia
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <sophia/console/console_command_registry.hpp>
|
||||||
#include <sophia/handles.hpp>
|
#include <sophia/handles.hpp>
|
||||||
#include <sophia/ui/panel_registry.hpp>
|
#include <sophia/ui/panel_registry.hpp>
|
||||||
|
|
||||||
@@ -10,7 +11,7 @@ class DebugUI {
|
|||||||
DebugUI(const DebugUI&) = delete;
|
DebugUI(const DebugUI&) = delete;
|
||||||
DebugUI& operator=(const DebugUI&) = delete;
|
DebugUI& operator=(const DebugUI&) = delete;
|
||||||
|
|
||||||
explicit DebugUI(PanelRegistry& registry);
|
DebugUI(PanelRegistry& registry, ConsoleCommandRegistry& commands);
|
||||||
~DebugUI() = default;
|
~DebugUI() = default;
|
||||||
|
|
||||||
void show();
|
void show();
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ Application::Application(const Config& config)
|
|||||||
canvas{this},
|
canvas{this},
|
||||||
args{std::move(commandLineArgs)},
|
args{std::move(commandLineArgs)},
|
||||||
assetRegistry{impl->getDevice()},
|
assetRegistry{impl->getDevice()},
|
||||||
_debugUI{this->panelRegistry} {}
|
_debugUI{this->panelRegistry, this->consoleCommandRegistry} {}
|
||||||
|
|
||||||
Application::~Application() = default;
|
Application::~Application() = default;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#include <sophia/console/console_command_registry.hpp>
|
||||||
|
|
||||||
|
namespace sophia {
|
||||||
|
|
||||||
|
void ConsoleCommandRegistry::registerCommand(std::string name, std::string help,
|
||||||
|
Handler handler) {
|
||||||
|
commands[std::move(name)] = Command{std::move(help), std::move(handler)};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConsoleCommandRegistry::dispatch(const std::string& name,
|
||||||
|
const std::vector<std::string>& args,
|
||||||
|
std::string& outResult) const {
|
||||||
|
auto it = commands.find(name);
|
||||||
|
if (it == commands.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
outResult = it->second.handler(args);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ConsoleCommandRegistry::CommandInfo> ConsoleCommandRegistry::list()
|
||||||
|
const {
|
||||||
|
std::vector<CommandInfo> result;
|
||||||
|
result.reserve(commands.size());
|
||||||
|
for (const auto& [name, command] : commands) {
|
||||||
|
result.push_back(CommandInfo{name, command.help});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sophia
|
||||||
@@ -6,11 +6,12 @@
|
|||||||
|
|
||||||
namespace sophia {
|
namespace sophia {
|
||||||
|
|
||||||
DebugUI::DebugUI(PanelRegistry& registry) : registry{registry} {
|
DebugUI::DebugUI(PanelRegistry& registry, ConsoleCommandRegistry& commands)
|
||||||
|
: registry{registry} {
|
||||||
// #ifndef NDEBUG
|
// #ifndef NDEBUG
|
||||||
this->panelRegistryHandle = registry.emplace<PanelRegistryPanel>(registry);
|
this->panelRegistryHandle = registry.emplace<PanelRegistryPanel>(registry);
|
||||||
this->frameStatsHandle = registry.emplace<FrameStatsPanel>();
|
this->frameStatsHandle = registry.emplace<FrameStatsPanel>();
|
||||||
this->consoleHandle = registry.emplace<ConsolePanel>();
|
this->consoleHandle = registry.emplace<ConsolePanel>(commands);
|
||||||
// #endif // !NDEBUG
|
// #endif // !NDEBUG
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "console_panel.hpp"
|
#include "console_panel.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
namespace sophia {
|
namespace sophia {
|
||||||
|
|
||||||
@@ -11,10 +12,6 @@ constexpr ImVec4 COLOR_ERROR = ImVec4(1.0f, 0.4f, 0.4f, 1.0f);
|
|||||||
constexpr ImVec4 COLOR_INFO = ImVec4(0.4f, 0.7f, 1.0f, 1.0f);
|
constexpr ImVec4 COLOR_INFO = ImVec4(0.4f, 0.7f, 1.0f, 1.0f);
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void ConsolePanel::registerDefaultCommands() {
|
|
||||||
log("Console ready. Type 'help' for a list of commands.");
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConsolePanel::log(const std::string& message) {
|
void ConsolePanel::log(const std::string& message) {
|
||||||
entries.push_back(Entry{message, COLOR_DEFAULT});
|
entries.push_back(Entry{message, COLOR_DEFAULT});
|
||||||
scrollToBottom = true;
|
scrollToBottom = true;
|
||||||
@@ -22,6 +19,16 @@ void ConsolePanel::log(const std::string& message) {
|
|||||||
|
|
||||||
void ConsolePanel::clear() { entries.clear(); }
|
void ConsolePanel::clear() { entries.clear(); }
|
||||||
|
|
||||||
|
std::vector<std::string> ConsolePanel::tokenize(const std::string& command) {
|
||||||
|
std::istringstream stream(command);
|
||||||
|
std::vector<std::string> tokens;
|
||||||
|
std::string token;
|
||||||
|
while (stream >> token) {
|
||||||
|
tokens.push_back(std::move(token));
|
||||||
|
}
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
|
||||||
void ConsolePanel::execute(const std::string& command) {
|
void ConsolePanel::execute(const std::string& command) {
|
||||||
entries.push_back(Entry{"> " + command, COLOR_COMMAND});
|
entries.push_back(Entry{"> " + command, COLOR_COMMAND});
|
||||||
scrollToBottom = true;
|
scrollToBottom = true;
|
||||||
@@ -31,19 +38,47 @@ void ConsolePanel::execute(const std::string& command) {
|
|||||||
history.end());
|
history.end());
|
||||||
history.push_back(command);
|
history.push_back(command);
|
||||||
|
|
||||||
if (command == "help") {
|
std::vector<std::string> tokens = tokenize(command);
|
||||||
entries.push_back(
|
if (tokens.empty()) {
|
||||||
Entry{"Available commands: help, clear, history", COLOR_INFO});
|
return;
|
||||||
} else if (command == "clear") {
|
}
|
||||||
|
|
||||||
|
const std::string& name = tokens.front();
|
||||||
|
const std::vector<std::string> args(tokens.begin() + 1, tokens.end());
|
||||||
|
|
||||||
|
if (name == "help") {
|
||||||
|
entries.push_back(Entry{"help - List available commands", COLOR_INFO});
|
||||||
|
entries.push_back(Entry{"clear - Clear the console output", COLOR_INFO});
|
||||||
|
entries.push_back(Entry{"history - Show command history", COLOR_INFO});
|
||||||
|
for (const auto& info : consoleCommandRegistry.list()) {
|
||||||
|
entries.push_back(Entry{info.name + " - " + info.help, COLOR_INFO});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name == "clear") {
|
||||||
clear();
|
clear();
|
||||||
} else if (command == "history") {
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name == "history") {
|
||||||
for (const std::string& past : history) {
|
for (const std::string& past : history) {
|
||||||
entries.push_back(Entry{past, COLOR_DEFAULT});
|
entries.push_back(Entry{past, COLOR_DEFAULT});
|
||||||
}
|
}
|
||||||
} else if (commandCallback) {
|
return;
|
||||||
commandCallback(*this, command);
|
}
|
||||||
|
|
||||||
|
std::string result;
|
||||||
|
try {
|
||||||
|
if (consoleCommandRegistry.dispatch(name, args, result)) {
|
||||||
|
if (!result.empty()) {
|
||||||
|
entries.push_back(Entry{result, COLOR_INFO});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
entries.push_back(Entry{"Unknown command: '" + command + "'", COLOR_ERROR});
|
entries.push_back(Entry{"Unknown command: '" + name + "'", COLOR_ERROR});
|
||||||
|
}
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
entries.push_back(Entry{e.what(), COLOR_ERROR});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,8 +116,6 @@ void ConsolePanel::onUpdate(const FrameInfo&) {
|
|||||||
if (ImGui::SmallButton("Clear")) {
|
if (ImGui::SmallButton("Clear")) {
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::Checkbox("Auto-scroll", &autoScroll);
|
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
@@ -97,8 +130,7 @@ void ConsolePanel::onUpdate(const FrameInfo&) {
|
|||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scrollToBottom ||
|
if (scrollToBottom) {
|
||||||
(autoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())) {
|
|
||||||
ImGui::SetScrollHereY(1.0f);
|
ImGui::SetScrollHereY(1.0f);
|
||||||
}
|
}
|
||||||
scrollToBottom = false;
|
scrollToBottom = false;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
|
||||||
#include <functional>
|
#include <sophia/console/console_command_registry.hpp>
|
||||||
#include <sophia/frame_info.hpp>
|
#include <sophia/frame_info.hpp>
|
||||||
#include <sophia/ui/panel.hpp>
|
#include <sophia/ui/panel.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -12,39 +12,34 @@ namespace sophia {
|
|||||||
|
|
||||||
class ConsolePanel : public Panel {
|
class ConsolePanel : public Panel {
|
||||||
public:
|
public:
|
||||||
using CommandCallback =
|
explicit ConsolePanel(ConsoleCommandRegistry& consoleCommandRegistry)
|
||||||
std::function<void(ConsolePanel&, const std::string&)>;
|
: Panel{"Console"}, consoleCommandRegistry{consoleCommandRegistry} {
|
||||||
|
log("Console ready. Type 'help' for a list of commands.");
|
||||||
ConsolePanel() : Panel{"Console"} { registerDefaultCommands(); }
|
}
|
||||||
|
|
||||||
void onUpdate(const FrameInfo& frameInfo) override;
|
void onUpdate(const FrameInfo& frameInfo) override;
|
||||||
|
|
||||||
void log(const std::string& message);
|
void log(const std::string& message);
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
void setCommandCallback(CommandCallback callback) {
|
|
||||||
this->commandCallback = std::move(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Entry {
|
struct Entry {
|
||||||
std::string text;
|
std::string text;
|
||||||
ImVec4 color;
|
ImVec4 color;
|
||||||
};
|
};
|
||||||
|
|
||||||
void registerDefaultCommands();
|
|
||||||
void execute(const std::string& command);
|
void execute(const std::string& command);
|
||||||
int textEditCallback(struct ImGuiInputTextCallbackData* data);
|
int textEditCallback(struct ImGuiInputTextCallbackData* data);
|
||||||
|
static std::vector<std::string> tokenize(const std::string& command);
|
||||||
|
|
||||||
std::vector<Entry> entries;
|
std::vector<Entry> entries;
|
||||||
std::vector<std::string> history;
|
std::vector<std::string> history;
|
||||||
int historyPos = -1;
|
int historyPos = -1;
|
||||||
|
|
||||||
char inputBuffer[256] = {};
|
char inputBuffer[256] = {};
|
||||||
bool autoScroll = true;
|
|
||||||
bool scrollToBottom = false;
|
bool scrollToBottom = false;
|
||||||
|
|
||||||
CommandCallback commandCallback;
|
ConsoleCommandRegistry& consoleCommandRegistry;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sophia
|
} // namespace sophia
|
||||||
|
|||||||
Reference in New Issue
Block a user