From 9096da19f115bfd7e3a187fcd0611e89e062a5db Mon Sep 17 00:00:00 2001 From: Marco Cutecchia Date: Fri, 18 Mar 2022 23:17:22 +0100 Subject: [PATCH] HackStudio: Allow customizing the actions of the Build & Run buttons This commit introduces per-project settings that can be customized through a JSON file placed in '.hackstudio/config.json' in the project's root --- Userland/DevTools/HackStudio/CMakeLists.txt | 1 + Userland/DevTools/HackStudio/Project.cpp | 9 ++++ Userland/DevTools/HackStudio/Project.h | 4 ++ .../DevTools/HackStudio/ProjectBuilder.cpp | 12 +++++ Userland/DevTools/HackStudio/ProjectBuilder.h | 1 + .../DevTools/HackStudio/ProjectConfig.cpp | 46 +++++++++++++++++++ Userland/DevTools/HackStudio/ProjectConfig.h | 33 +++++++++++++ 7 files changed, 106 insertions(+) create mode 100644 Userland/DevTools/HackStudio/ProjectConfig.cpp create mode 100644 Userland/DevTools/HackStudio/ProjectConfig.h diff --git a/Userland/DevTools/HackStudio/CMakeLists.txt b/Userland/DevTools/HackStudio/CMakeLists.txt index 610b25ef35..ffdfca0a48 100644 --- a/Userland/DevTools/HackStudio/CMakeLists.txt +++ b/Userland/DevTools/HackStudio/CMakeLists.txt @@ -44,6 +44,7 @@ set(SOURCES Locator.cpp Project.cpp ProjectBuilder.cpp + ProjectConfig.cpp ProjectDeclarations.cpp ProjectFile.cpp ProjectTemplate.cpp diff --git a/Userland/DevTools/HackStudio/Project.cpp b/Userland/DevTools/HackStudio/Project.cpp index ed91439b87..9766039281 100644 --- a/Userland/DevTools/HackStudio/Project.cpp +++ b/Userland/DevTools/HackStudio/Project.cpp @@ -66,4 +66,13 @@ bool Project::project_is_serenity() const return m_root_path.ends_with("Source/serenity"); } +NonnullOwnPtr Project::config() const +{ + auto config_or_error = ProjectConfig::try_load_project_config(LexicalPath::absolute_path(m_root_path, config_file_path)); + if (config_or_error.is_error()) + return ProjectConfig::create_empty(); + + return config_or_error.release_value(); +} + } diff --git a/Userland/DevTools/HackStudio/Project.h b/Userland/DevTools/HackStudio/Project.h index 7763cfe752..53069481f4 100644 --- a/Userland/DevTools/HackStudio/Project.h +++ b/Userland/DevTools/HackStudio/Project.h @@ -6,6 +6,7 @@ #pragma once +#include "ProjectConfig.h" #include "ProjectFile.h" #include #include @@ -32,6 +33,9 @@ public: String to_absolute_path(String const&) const; bool project_is_serenity() const; + static constexpr StringView config_file_path = ".hackstudio/config.json"; + NonnullOwnPtr config() const; + private: explicit Project(String const& root_path); diff --git a/Userland/DevTools/HackStudio/ProjectBuilder.cpp b/Userland/DevTools/HackStudio/ProjectBuilder.cpp index e5d924fbbb..1052fd3ed2 100644 --- a/Userland/DevTools/HackStudio/ProjectBuilder.cpp +++ b/Userland/DevTools/HackStudio/ProjectBuilder.cpp @@ -16,6 +16,7 @@ namespace HackStudio { ProjectBuilder::ProjectBuilder(NonnullRefPtr terminal, Project const& project) : m_project_root(project.root_path()) + , m_project(project) , m_terminal(move(terminal)) , m_is_serenity(project.project_is_serenity() ? IsSerenityRepo::Yes : IsSerenityRepo::No) { @@ -24,6 +25,12 @@ ProjectBuilder::ProjectBuilder(NonnullRefPtr terminal, Project ErrorOr ProjectBuilder::build(StringView active_file) { m_terminal->clear_including_history(); + + if (auto command = m_project.config()->build_command(); command.has_value()) { + TRY(m_terminal->run_command(command.value())); + return {}; + } + if (active_file.is_null()) return Error::from_string_literal("no active file"sv); @@ -44,6 +51,11 @@ ErrorOr ProjectBuilder::build(StringView active_file) ErrorOr ProjectBuilder::run(StringView active_file) { + if (auto command = m_project.config()->run_command(); command.has_value()) { + TRY(m_terminal->run_command(command.value())); + return {}; + } + if (active_file.is_null()) return Error::from_string_literal("no active file"sv); diff --git a/Userland/DevTools/HackStudio/ProjectBuilder.h b/Userland/DevTools/HackStudio/ProjectBuilder.h index d7d1a00f16..22766788e4 100644 --- a/Userland/DevTools/HackStudio/ProjectBuilder.h +++ b/Userland/DevTools/HackStudio/ProjectBuilder.h @@ -49,6 +49,7 @@ private: static ErrorOr verify_cmake_is_installed(); String m_project_root; + Project const& m_project; NonnullRefPtr m_terminal; IsSerenityRepo m_is_serenity { IsSerenityRepo::No }; String m_serenity_component_cmake_file; diff --git a/Userland/DevTools/HackStudio/ProjectConfig.cpp b/Userland/DevTools/HackStudio/ProjectConfig.cpp new file mode 100644 index 0000000000..2f064870c6 --- /dev/null +++ b/Userland/DevTools/HackStudio/ProjectConfig.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "ProjectConfig.h" +#include +#include + +namespace HackStudio { + +ProjectConfig::ProjectConfig(JsonObject config) + : m_config(move(config)) +{ +} + +ErrorOr> ProjectConfig::try_load_project_config(String path) +{ + auto file = TRY(Core::File::open(path, Core::OpenMode::ReadOnly)); + auto file_contents = file->read_all(); + file->close(); + + auto json = TRY(JsonValue::from_string(StringView { file_contents })); + if (!json.is_object()) + return Error::from_string_literal("The topmost JSON element is not an object"); + + return adopt_own(*new ProjectConfig(json.as_object())); +} + +NonnullOwnPtr ProjectConfig::create_empty() +{ + JsonObject empty {}; + return adopt_own(*new ProjectConfig(empty)); +} + +Optional ProjectConfig::read_key(String key_name) const +{ + auto const& value = m_config.get(key_name); + if (!value.is_string()) + return {}; + + return { value.as_string() }; +} + +} diff --git a/Userland/DevTools/HackStudio/ProjectConfig.h b/Userland/DevTools/HackStudio/ProjectConfig.h new file mode 100644 index 0000000000..f916de3567 --- /dev/null +++ b/Userland/DevTools/HackStudio/ProjectConfig.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace HackStudio { + +class ProjectConfig { +public: + static ErrorOr> try_load_project_config(String path); + static NonnullOwnPtr create_empty(); + + ProjectConfig(JsonObject); + + Optional build_command() const { return read_key("build_command"); } + Optional run_command() const { return read_key("run_command"); } + +private: + Optional read_key(String key_name) const; + + JsonObject m_config; +}; + +}