diff --git a/src/olympic/studio/applib/src/CMakeLists.txt b/src/olympic/studio/applib/src/CMakeLists.txt index 5fc2a173..2cd25907 100644 --- a/src/olympic/studio/applib/src/CMakeLists.txt +++ b/src/olympic/studio/applib/src/CMakeLists.txt @@ -47,3 +47,5 @@ install( LIBRARY DESTINATION lib ARCHIVE DESTINATION lib ) + +add_subdirectory(subcommands) \ No newline at end of file diff --git a/src/olympic/studio/applib/src/app.cpp b/src/olympic/studio/applib/src/app.cpp index 186d84f9..badf1554 100644 --- a/src/olympic/studio/applib/src/app.cpp +++ b/src/olympic/studio/applib/src/app.cpp @@ -14,24 +14,68 @@ #include #include +#include "subcommands/change-format/change-format.hpp" + +#include "configfile.hpp" #include "studioui.hpp" 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 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 converters() const noexcept override { + return { + keel::Converter::make(), + }; + } +} constexpr kmod; + + class StudioUIDrawer: public turbine::gl::Drawer { private: StudioUI &m_ui; public: explicit StudioUIDrawer(StudioUI &ui) noexcept: m_ui(ui) { } - protected: + void draw(turbine::Context&) noexcept final { m_ui.draw(); } }; -static void keyEventHandler(turbine::Context &ctx, turbine::Key key, bool down) noexcept { - auto const sctx = turbine::applicationData(ctx); +static void keyEventHandler(turbine::Context &ctx, turbine::Key const key, bool const down) noexcept { + auto const sctx = turbine::applicationData(ctx); sctx->ui.handleKeyEvent(key, down); } @@ -65,6 +109,8 @@ static ox::Error run( ox::StringViewCR appName, ox::StringViewCR projectDataDir, ox::SpanView const &args) { + keel::registerModule(kmod); + registerModule(&mod); // seed UUID generator auto const time = std::time(nullptr); ox::UUID::seedGenerator({ diff --git a/src/olympic/studio/applib/src/configfile.hpp b/src/olympic/studio/applib/src/configfile.hpp new file mode 100644 index 00000000..c1e193b0 --- /dev/null +++ b/src/olympic/studio/applib/src/configfile.hpp @@ -0,0 +1,68 @@ +/* + * Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +#include +#include + +#include + +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 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 openFiles; + }; + ox::Vector 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; + +} diff --git a/src/olympic/studio/applib/src/subcommands/CMakeLists.txt b/src/olympic/studio/applib/src/subcommands/CMakeLists.txt new file mode 100644 index 00000000..737afc34 --- /dev/null +++ b/src/olympic/studio/applib/src/subcommands/CMakeLists.txt @@ -0,0 +1,10 @@ + +target_sources( + StudioAppLib PRIVATE + change-format/change-format.cpp +) + +target_link_libraries( + StudioAppLib PUBLIC + OxClArgs +) \ No newline at end of file diff --git a/src/olympic/studio/applib/src/subcommands/change-format/change-format.cpp b/src/olympic/studio/applib/src/subcommands/change-format/change-format.cpp new file mode 100644 index 00000000..465be09d --- /dev/null +++ b/src/olympic/studio/applib/src/subcommands/change-format/change-format.cpp @@ -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 +#include + +#include + +#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 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 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 {}; +} + +} diff --git a/src/olympic/studio/applib/src/subcommands/change-format/change-format.hpp b/src/olympic/studio/applib/src/subcommands/change-format/change-format.hpp new file mode 100644 index 00000000..7fc1f695 --- /dev/null +++ b/src/olympic/studio/applib/src/subcommands/change-format/change-format.hpp @@ -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 args) noexcept; + +} \ No newline at end of file diff --git a/src/olympic/studio/modlib/include/studio/project.hpp b/src/olympic/studio/modlib/include/studio/project.hpp index aa56bb0b..d43dd70b 100644 --- a/src/olympic/studio/modlib/include/studio/project.hpp +++ b/src/olympic/studio/modlib/include/studio/project.hpp @@ -122,6 +122,16 @@ class Project: public ox::SignalHandler { 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: void buildFileIndex() noexcept; diff --git a/src/olympic/studio/modlib/src/project.cpp b/src/olympic/studio/modlib/src/project.cpp index 73122252..3e4658d9 100644 --- a/src/olympic/studio/modlib/src/project.cpp +++ b/src/olympic/studio/modlib/src/project.cpp @@ -14,13 +14,15 @@ namespace studio { 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(parentDir("/a/b/c") == "/a/b"); static_assert(parentDir("/a/b/c/") == "/a/b"); static void generateTypes(ox::TypeStore &ts) noexcept { for (auto const mod : keel::modules()) { - for (auto gen : mod->types()) { + for (auto const gen : mod->types()) { oxLogError(gen(ts)); } }