This commit is contained in:
@@ -47,3 +47,5 @@ install(
|
|||||||
LIBRARY DESTINATION lib
|
LIBRARY DESTINATION lib
|
||||||
ARCHIVE DESTINATION lib
|
ARCHIVE DESTINATION lib
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_subdirectory(subcommands)
|
||||||
@@ -14,24 +14,68 @@
|
|||||||
#include <studio/context.hpp>
|
#include <studio/context.hpp>
|
||||||
#include <studioapp/studioapp.hpp>
|
#include <studioapp/studioapp.hpp>
|
||||||
|
|
||||||
|
#include "subcommands/change-format/change-format.hpp"
|
||||||
|
|
||||||
|
#include "configfile.hpp"
|
||||||
#include "studioui.hpp"
|
#include "studioui.hpp"
|
||||||
|
|
||||||
namespace studio {
|
namespace studio {
|
||||||
|
|
||||||
|
static ox::Error convertStudioConfigV1ToStudioConfigV2(
|
||||||
|
keel::Context&,
|
||||||
|
StudioConfigV1 &src,
|
||||||
|
StudioConfigV2 &dst) noexcept {
|
||||||
|
dst.projects.emplace_back(StudioConfigV2::ProjectConfig{
|
||||||
|
.projectPath = std::move(src.projectPath),
|
||||||
|
.activeTabItemName = std::move(src.activeTabItemName),
|
||||||
|
.openFiles = std::move(src.openFiles),
|
||||||
|
});
|
||||||
|
dst.showProjectExplorer = src.showProjectExplorer;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct: Module {
|
||||||
|
ox::String id() const noexcept final {
|
||||||
|
return ox::String{"net.drinkingtea.studio"};
|
||||||
|
}
|
||||||
|
|
||||||
|
ox::Vector<Command> commands() const final {
|
||||||
|
return {
|
||||||
|
{
|
||||||
|
"change-format",
|
||||||
|
cmdChangeFormat,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} constexpr mod;
|
||||||
|
|
||||||
|
static struct: keel::Module {
|
||||||
|
ox::String id() const noexcept override {
|
||||||
|
return ox::String{"net.drinkingtea.studio"};
|
||||||
|
}
|
||||||
|
|
||||||
|
ox::Vector<keel::Converter> converters() const noexcept override {
|
||||||
|
return {
|
||||||
|
keel::Converter::make<convertStudioConfigV1ToStudioConfigV2>(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} constexpr kmod;
|
||||||
|
|
||||||
|
|
||||||
class StudioUIDrawer: public turbine::gl::Drawer {
|
class StudioUIDrawer: public turbine::gl::Drawer {
|
||||||
private:
|
private:
|
||||||
StudioUI &m_ui;
|
StudioUI &m_ui;
|
||||||
public:
|
public:
|
||||||
explicit StudioUIDrawer(StudioUI &ui) noexcept: m_ui(ui) {
|
explicit StudioUIDrawer(StudioUI &ui) noexcept: m_ui(ui) {
|
||||||
}
|
}
|
||||||
protected:
|
|
||||||
void draw(turbine::Context&) noexcept final {
|
void draw(turbine::Context&) noexcept final {
|
||||||
m_ui.draw();
|
m_ui.draw();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void keyEventHandler(turbine::Context &ctx, turbine::Key key, bool down) noexcept {
|
static void keyEventHandler(turbine::Context &ctx, turbine::Key const key, bool const down) noexcept {
|
||||||
auto const sctx = turbine::applicationData<studio::Context>(ctx);
|
auto const sctx = turbine::applicationData<Context>(ctx);
|
||||||
sctx->ui.handleKeyEvent(key, down);
|
sctx->ui.handleKeyEvent(key, down);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,6 +109,8 @@ static ox::Error run(
|
|||||||
ox::StringViewCR appName,
|
ox::StringViewCR appName,
|
||||||
ox::StringViewCR projectDataDir,
|
ox::StringViewCR projectDataDir,
|
||||||
ox::SpanView<ox::CString> const &args) {
|
ox::SpanView<ox::CString> const &args) {
|
||||||
|
keel::registerModule(kmod);
|
||||||
|
registerModule(&mod);
|
||||||
// seed UUID generator
|
// seed UUID generator
|
||||||
auto const time = std::time(nullptr);
|
auto const time = std::time(nullptr);
|
||||||
ox::UUID::seedGenerator({
|
ox::UUID::seedGenerator({
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ox/std/string.hpp>
|
||||||
|
#include <ox/std/vector.hpp>
|
||||||
|
|
||||||
|
#include <ox/model/def.hpp>
|
||||||
|
|
||||||
|
namespace studio {
|
||||||
|
|
||||||
|
struct StudioConfigV1 {
|
||||||
|
static constexpr auto TypeName = "net.drinkingtea.studio.StudioConfig";
|
||||||
|
static constexpr auto TypeVersion = 1;
|
||||||
|
ox::String projectPath;
|
||||||
|
ox::String activeTabItemName;
|
||||||
|
ox::Vector<ox::String> openFiles;
|
||||||
|
bool showProjectExplorer = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
OX_MODEL_BEGIN(StudioConfigV1)
|
||||||
|
OX_MODEL_FIELD_RENAME(activeTabItemName, active_tab_item_name)
|
||||||
|
OX_MODEL_FIELD_RENAME(projectPath, project_path)
|
||||||
|
OX_MODEL_FIELD_RENAME(openFiles, open_files)
|
||||||
|
OX_MODEL_FIELD_RENAME(showProjectExplorer, show_project_explorer)
|
||||||
|
OX_MODEL_END()
|
||||||
|
|
||||||
|
|
||||||
|
struct StudioConfigV2 {
|
||||||
|
static constexpr auto TypeName = "net.drinkingtea.studio.StudioConfig";
|
||||||
|
static constexpr auto TypeVersion = 2;
|
||||||
|
struct ProjectConfig {
|
||||||
|
static constexpr auto TypeName = "net.drinkingtea.studio.ProjectConfig";
|
||||||
|
static constexpr auto TypeVersion = 2;
|
||||||
|
ox::String projectPath;
|
||||||
|
ox::String activeTabItemName;
|
||||||
|
ox::Vector<ox::String> openFiles;
|
||||||
|
};
|
||||||
|
ox::Vector<ProjectConfig> projects;
|
||||||
|
bool showProjectExplorer = true;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr ProjectConfig const *project() const {
|
||||||
|
return projects.empty() ? nullptr : &projects[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr ProjectConfig *project() {
|
||||||
|
return projects.empty() ? nullptr : &projects[0];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
OX_MODEL_BEGIN(StudioConfigV2::ProjectConfig)
|
||||||
|
OX_MODEL_FIELD_RENAME(activeTabItemName, active_tab_item_name)
|
||||||
|
OX_MODEL_FIELD_RENAME(projectPath, project_path)
|
||||||
|
OX_MODEL_FIELD_RENAME(openFiles, open_files)
|
||||||
|
OX_MODEL_END()
|
||||||
|
|
||||||
|
OX_MODEL_BEGIN(StudioConfigV2)
|
||||||
|
OX_MODEL_FIELD(projects)
|
||||||
|
OX_MODEL_FIELD_RENAME(showProjectExplorer, show_project_explorer)
|
||||||
|
OX_MODEL_END()
|
||||||
|
|
||||||
|
using StudioConfig = StudioConfigV2;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
target_sources(
|
||||||
|
StudioAppLib PRIVATE
|
||||||
|
change-format/change-format.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
StudioAppLib PUBLIC
|
||||||
|
OxClArgs
|
||||||
|
)
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 - 2026 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ox/clargs/clargs.hpp>
|
||||||
|
#include <ox/std/trace.hpp>
|
||||||
|
|
||||||
|
#include <studio/project.hpp>
|
||||||
|
|
||||||
|
#include "change-format.hpp"
|
||||||
|
|
||||||
|
namespace studio {
|
||||||
|
|
||||||
|
static ox::Error convertFile(
|
||||||
|
ox::FileSystem &fs,
|
||||||
|
ox::TypeStore &ts,
|
||||||
|
ox::StringViewCR path,
|
||||||
|
ox::ClawFormat const fmt) noexcept {
|
||||||
|
ox::Buffer buff;
|
||||||
|
ox::ModelObject obj;
|
||||||
|
OX_RETURN_ERROR(fs.read(path).moveTo(buff).reoriginate(1, "unable to read file"));
|
||||||
|
OX_RETURN_ERROR(keel::readAsset(ts, buff).moveTo(obj).reoriginate(1, "unable to parse file"));
|
||||||
|
OX_RETURN_ERROR(ox::writeClaw(obj, fmt).moveTo(buff));
|
||||||
|
OX_RETURN_ERROR(fs.write(path, buff).reoriginate(1, "unable to write file"));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printUsage() noexcept {
|
||||||
|
oxErr(R"(usage: convert-file {mc,oc} [files...]\n)");
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
static constexpr ox::Result<ox::ClawFormat> getFmt(ox::StringViewCR fmtStr) noexcept {
|
||||||
|
if (fmtStr == "mc") {
|
||||||
|
return ox::ClawFormat::Metal;
|
||||||
|
} else if (fmtStr == "oc") {
|
||||||
|
return ox::ClawFormat::Metal;
|
||||||
|
}
|
||||||
|
return ox::Error(1, "invalid format");
|
||||||
|
}
|
||||||
|
|
||||||
|
ox::Error cmdChangeFormat(Project &project, ox::SpanView<ox::CString> const args) noexcept {
|
||||||
|
if (args.size() < 2) {
|
||||||
|
printUsage();
|
||||||
|
return ox::Error{1, "invalid input"};
|
||||||
|
}
|
||||||
|
auto const [fmt, fmtErr] = getFmt(args[0]);
|
||||||
|
if (fmtErr) {
|
||||||
|
printUsage();
|
||||||
|
}
|
||||||
|
auto &fs = project.romFs();
|
||||||
|
auto &ts = project.typeStore();
|
||||||
|
for (auto const &file : args + 1) {
|
||||||
|
auto const err = convertFile(fs, ts, file, fmt);
|
||||||
|
if (err) {
|
||||||
|
oxErrf("Failed to convert {}: {}\n", file, err.msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 - 2026 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace studio {
|
||||||
|
|
||||||
|
ox::Error cmdChangeFormat(Project &project, ox::SpanView<ox::CString> args) noexcept;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -122,6 +122,16 @@ class Project: public ox::SignalHandler {
|
|||||||
|
|
||||||
ox::Error writeTypeStore() noexcept;
|
ox::Error writeTypeStore() noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr ox::TypeStore &typeStore() noexcept {
|
||||||
|
return m_typeStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr ox::TypeStore const &typeStore() const noexcept {
|
||||||
|
return m_typeStore;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void buildFileIndex() noexcept;
|
void buildFileIndex() noexcept;
|
||||||
|
|
||||||
|
|||||||
@@ -14,13 +14,15 @@
|
|||||||
namespace studio {
|
namespace studio {
|
||||||
|
|
||||||
static_assert(fileExt("main.c").value == "c");
|
static_assert(fileExt("main.c").value == "c");
|
||||||
|
static_assert(fileExt("main.cc").value == "cc");
|
||||||
|
static_assert(fileExt("main.cpp").value == "cpp");
|
||||||
static_assert(fileExt("a.b.c").value == "c");
|
static_assert(fileExt("a.b.c").value == "c");
|
||||||
static_assert(parentDir("/a/b/c") == "/a/b");
|
static_assert(parentDir("/a/b/c") == "/a/b");
|
||||||
static_assert(parentDir("/a/b/c/") == "/a/b");
|
static_assert(parentDir("/a/b/c/") == "/a/b");
|
||||||
|
|
||||||
static void generateTypes(ox::TypeStore &ts) noexcept {
|
static void generateTypes(ox::TypeStore &ts) noexcept {
|
||||||
for (auto const mod : keel::modules()) {
|
for (auto const mod : keel::modules()) {
|
||||||
for (auto gen : mod->types()) {
|
for (auto const gen : mod->types()) {
|
||||||
oxLogError(gen(ts));
|
oxLogError(gen(ts));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user