/** * @file code.cpp * @brief Contains code for algorithm-code-related UI elements and logic. * * Copyright (C) 2021 Clyne Sullivan * * Distributed under the GNU GPL v3 or later. You should have received a copy of * the GNU General Public License along with this program. * If not, see . */ #include "imgui.h" #include "backends/imgui_impl_sdl.h" #include "backends/imgui_impl_opengl2.h" #include "TextEditor.h" #include "config.h" #include "stmdsp.hpp" #include "stmdsp_code.hpp" #include #include #include #include #include extern std::shared_ptr m_device; extern void log(const std::string& str); TextEditor editor; // file.cpp std::string tempFileName; // device.cpp static std::string editorCompiled; static std::string newTempFileName(); static bool codeExecuteCommand(const std::string& command, const std::string& file); static void stringReplaceAll(std::string& str, const std::string& what, const std::string& with); static void compileEditorCode(); static void disassembleCode(); void codeEditorInit() { editor.SetLanguageDefinition(TextEditor::LanguageDefinition::CPlusPlus()); editor.SetPalette(TextEditor::GetLightPalette()); } void codeRenderMenu() { if (ImGui::BeginMenu("Code")) { if (ImGui::MenuItem("Compile code")) compileEditorCode(); if (ImGui::MenuItem("Show disassembly")) disassembleCode(); ImGui::EndMenu(); } } void codeRenderToolbar() { if (ImGui::Button("Compile")) compileEditorCode(); } void codeRenderWidgets() { editor.Render("code", {WINDOW_WIDTH - 15, 450}, true); } std::string newTempFileName() { const auto path = std::filesystem::temp_directory_path() / "stmdspgui_build"; return path.string(); } bool codeExecuteCommand(const std::string& command, const std::string& file) { if (system(command.c_str()) == 0) { if (std::ifstream output (file); output.good()) { std::ostringstream sstr; sstr << output.rdbuf(); log(sstr.str().c_str()); } else { log("Could not read command output!"); } std::filesystem::remove(file); return true; } else { return false; } } void stringReplaceAll(std::string& str, const std::string& what, const std::string& with) { std::size_t i; while ((i = str.find(what)) != std::string::npos) { str.replace(i, what.size(), with); i += what.size(); } }; void compileEditorCode() { log("Compiling..."); // Scrap cached build if there are changes if (editor.GetText().compare(editorCompiled) != 0) { std::filesystem::remove(tempFileName + ".o"); std::filesystem::remove(tempFileName + ".orig.o"); } const auto platform = m_device ? m_device->get_platform() : stmdsp::platform::L4; if (tempFileName.empty()) tempFileName = newTempFileName(); { std::ofstream file (tempFileName, std::ios::trunc | std::ios::binary); auto file_text = platform == stmdsp::platform::L4 ? stmdsp::file_header_l4 : stmdsp::file_header_h7; const auto buffer_size = m_device ? m_device->get_buffer_size() : stmdsp::SAMPLES_MAX; stringReplaceAll(file_text, "$0", std::to_string(buffer_size)); file << file_text << '\n' << editor.GetText(); } const auto scriptFile = tempFileName + #ifndef STMDSP_WIN32 ".sh"; #else ".bat"; #endif { std::ofstream makefile (scriptFile, std::ios::binary); auto make_text = platform == stmdsp::platform::L4 ? stmdsp::makefile_text_l4 : stmdsp::makefile_text_h7; stringReplaceAll(make_text, "$0", tempFileName); stringReplaceAll(make_text, "$1", std::filesystem::current_path().string()); makefile << make_text; } #ifndef STMDSP_WIN32 system((std::string("chmod +x ") + scriptFile).c_str()); #endif const auto makeOutput = scriptFile + ".log"; const auto makeCommand = scriptFile + " > " + makeOutput + " 2>&1"; if (codeExecuteCommand(makeCommand, makeOutput)) { editorCompiled = editor.GetText(); log("Compilation succeeded."); } else { log("Compilation failed."); } std::filesystem::remove(tempFileName); std::filesystem::remove(scriptFile); } void disassembleCode() { log("Disassembling..."); if (tempFileName.size() == 0 || editor.GetText().compare(editorCompiled) != 0) { compileEditorCode(); } const auto output = tempFileName + ".asm.log"; const auto command = std::string("arm-none-eabi-objdump -d --no-show-raw-insn ") + tempFileName + ".orig.o > " + output + " 2>&1"; if (codeExecuteCommand(command, output)) { log("Ready."); } else { log("Failed to load disassembly."); } }