[ui] Basic project manager & initial zep editor integration.

This commit is contained in:
Alexander Arlt 2022-08-15 12:16:37 +02:00
parent 8ba06a8675
commit a3586847a3
12 changed files with 25695 additions and 5 deletions

24596
tools/solidity-ui/3rd/json.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -23,11 +23,21 @@ endforeach()
set(sources
${SOLIDITY_UI_ASSETS_HEADERS}
main.cpp
ui/CommandLineOptions.h
project/Project.cpp
project/Project.h
project/Manager.cpp
project/Manager.h
project/Testcases.cpp
project/Testcases.h
project/Editor.cpp
project/Editor.h
3rd/json.hpp
)
add_executable(solidity-ui ${sources})
target_link_libraries(solidity-ui PRIVATE solcli SYSTEM imgui zep imgui_memory_editor implot)
target_compile_definitions(solidity-ui PUBLIC CMAKE_SOURCE_DIR="${CMAKE_SOURCE_DIR}")
target_include_directories(solidity-ui PUBLIC ${CMAKE_BINARY_DIR}/tools/solidity-ui)
target_include_directories(solidity-ui PUBLIC ${CMAKE_BINARY_DIR}/include ${CMAKE_BINARY_DIR}/tools/solidity-ui ${CMAKE_SOURCE_DIR})
include(GNUInstallDirs)

View File

@ -9,11 +9,41 @@
#endif
#include "assets/JetBrainsMono-Regular.ttf.h"
#include "libsolidity/interface/CompilerStack.h"
#include "libsolidity/interface/DebugSettings.h"
#include "project/Manager.h"
#include "project/Project.h"
#include "solc/CommandLineParser.h"
#include "solidity/BuildInfo.h"
#include "ui/CommandLineOptions.h"
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <iostream>
#include <memory>
#include <vector>
std::string createTooltipString(std::string const& string)
{
std::string result;
size_t length;
for (auto && ch : string)
{
result += ch;
++length;
if (length > 100)
{
result += "\n ";
length = 0;
}
}
return boost::trim_copy(result);
}
int main(int argc, char* argv[])
{
(void)argc;
(void)argv;
(void) argc;
(void) argv;
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0)
{
@ -74,12 +104,26 @@ int main(int argc, char* argv[])
// Load Fonts
auto font_data = new uint8_t[sizeof(solidity::ui::assets::JetBrainsMono_Regular_ttf)];
memcpy(font_data, solidity::ui::assets::JetBrainsMono_Regular_ttf, sizeof(solidity::ui::assets::JetBrainsMono_Regular_ttf));
memcpy(
font_data,
solidity::ui::assets::JetBrainsMono_Regular_ttf,
sizeof(solidity::ui::assets::JetBrainsMono_Regular_ttf));
// ownership of font_data will be transferred imgui
io.Fonts->AddFontFromMemoryTTF(font_data, sizeof(font_data), 16 * ImGui::GetPlatformIO().Monitors.begin()->DpiScale);
io.Fonts
->AddFontFromMemoryTTF(font_data, sizeof(font_data), 16 * ImGui::GetPlatformIO().Monitors.begin()->DpiScale);
// #2b2b2b
ImVec4 clear_color = ImVec4(0.169f, 0.169f, 0.169f, 1.00f);
// ImVec4 inactive_color = ImVec4(0.6f, 0.6f, 0.6f, 1.00f);
char solc_parameters[512];
memset(solc_parameters, 0, sizeof(solc_parameters));
char search_term[128];
memset(search_term, 0, sizeof(search_term));
std::string projectManagerConfig = boost::filesystem::current_path().generic_string() + "/solidity-ui.json";
solidity::ui::project::Manager& projectManager = solidity::ui::project::Manager::Instance();
projectManager.load(projectManagerConfig);
// Main loop
bool done = false;
@ -109,6 +153,122 @@ int main(int argc, char* argv[])
ImGui_ImplSDL2_NewFrame();
ImGui::NewFrame();
bool running = !done;
ImGui::Begin(
"solidity-ui",
&running,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse
| ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoSavedSettings
| ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_MenuBar);
ImGui::SetWindowPos(ImVec2{0, 0});
ImGui::SetWindowSize(io.DisplaySize);
if (ImGui::BeginMainMenuBar())
{
if (ImGui::BeginMenu("Solidity UI"))
{
ImGui::Separator();
ImGui::Text("Load Project");
ImGui::Text(" > via CLI");
ImGui::Text(" $ solc ");
ImGui::SameLine();
if (ImGui::InputTextWithHint(
"##0",
"<command line parameters>",
(char*) &solc_parameters,
sizeof(solc_parameters),
ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll))
{
memset(search_term, 0, sizeof(search_term));
projectManager.openProject(std::string(solc_parameters));
}
if (ImGui::BeginMenu(" > from Testcases"))
{
projectManager.testcases().renderMenuItems();
ImGui::EndMenu();
}
ImGui::Separator();
if (!projectManager.history().empty())
{
ImGui::Text("Project History");
ImGui::Text(" ");
ImGui::SameLine();
ImGui::InputTextWithHint(
"##1",
"<enter text to search history>",
search_term,
sizeof(search_term),
ImGuiInputTextFlags_AutoSelectAll);
}
std::string search(search_term);
solidity::ui::project::Manager::ProjectCache cache = projectManager.history(5, search);
for (auto& project: cache)
{
std::string project_simplified{project};
boost::replace_all(
project_simplified, CMAKE_SOURCE_DIR "/test/libsolidity/semanticTests/", "${semanticTests}/");
boost::replace_all(
project_simplified, CMAKE_SOURCE_DIR "/test/libsolidity/semanticTests", "${semanticTests}");
if (search.empty())
{
if (project_simplified.length() > 32)
project_simplified
= "[..]"
+ project_simplified
.substr(project_simplified.length() - 32, project_simplified.length());
}
if (ImGui::MenuItem((" $ solc " + project_simplified).c_str(), nullptr))
{
memset(search_term, 0, sizeof(search_term));
projectManager.openProject(project);
}
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
ImGui::SetTooltip("%s", createTooltipString(" $ solc " + project).c_str());
}
if (!projectManager.history().empty())
{
if (ImGui::BeginMenu(" Full Project History"))
{
for (auto& project: projectManager.history())
{
std::string project_simplified{project};
boost::replace_all(
project_simplified,
CMAKE_SOURCE_DIR "/test/libsolidity/semanticTests",
"${semanticTests}");
if (project_simplified.length() > 64)
project_simplified
= "[..]"
+ project_simplified
.substr(project_simplified.length() - 64, project_simplified.length());
if (ImGui::MenuItem((" $ solc " + project_simplified).c_str(), nullptr))
projectManager.openProject(project);
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
ImGui::SetTooltip("%s", createTooltipString(" $ solc " + project).c_str());
}
ImGui::EndMenu();
}
ImGui::Separator();
}
if (ImGui::MenuItem("Exit"))
{
done = true;
}
ImGui::EndMenu();
}
ImGui::EndMainMenuBar();
}
ImGui::End();
projectManager.render();
if (ImGui::BeginMainMenuBar())
{
if (ImGui::BeginMenu("v" ETH_PROJECT_VERSION "-" SOL_VERSION_PRERELEASE "+" SOL_VERSION_BUILDINFO, false))
ImGui::EndMenu();
ImGui::EndMainMenuBar();
}
// Rendering
ImGui::Render();
glViewport(0, 0, (int) io.DisplaySize.x, (int) io.DisplaySize.y);
@ -128,5 +288,7 @@ int main(int argc, char* argv[])
SDL_DestroyWindow(window);
SDL_Quit();
projectManager.save(projectManagerConfig);
return 0;
}

View File

@ -0,0 +1,155 @@
#if ZEP_SINGLE_HEADER == 1
#define ZEP_SINGLE_HEADER_BUILD
#endif
// #define ZEP_CONSOLE
#include "Editor.h"
#include "config_app.h"
#include <filesystem>
#include <functional>
#ifdef ZEP_CONSOLE
#include <zep\imgui\console_imgui.h>
#endif
#include "zep.h"
namespace fs = std::filesystem;
using namespace Zep;
using cmdFunc = std::function<void(const std::vector<std::string>&)>;
class ZepCmd: public ZepExCommand
{
public:
ZepCmd(ZepEditor& editor, const std::string name, cmdFunc fn): ZepExCommand(editor), m_name(name), m_func(fn) {}
virtual void Run(const std::vector<std::string>& args) override { m_func(args); }
virtual const char* ExCommandName() const override { return m_name.c_str(); }
private:
std::string m_name;
cmdFunc m_func;
};
struct ZepWrapper: public Zep::IZepComponent
{
ZepWrapper(
const fs::path& root_path,
const Zep::NVec2f& pixelScale,
std::function<void(std::shared_ptr<Zep::ZepMessage>)> fnCommandCB)
: zepEditor(Zep::ZepPath(root_path.string()), pixelScale), Callback(fnCommandCB)
{
zepEditor.RegisterCallback(this);
}
virtual ~ZepWrapper(){}
virtual Zep::ZepEditor& GetEditor() const override { return (Zep::ZepEditor&) zepEditor; }
virtual void Notify(std::shared_ptr<Zep::ZepMessage> message) override
{
Callback(message);
return;
}
virtual void HandleInput() { zepEditor.HandleInput(); }
Zep::ZepEditor_ImGui zepEditor;
std::function<void(std::shared_ptr<Zep::ZepMessage>)> Callback;
};
#ifdef ZEP_CONSOLE
std::shared_ptr<ImGui::ZepConsole> spZep;
#else
std::shared_ptr<ZepWrapper> spZep;
#endif
void zep_init(const Zep::NVec2f& pixelScale)
{
#ifdef ZEP_CONSOLE
spZep = std::make_shared<ImGui::ZepConsole>(Zep::ZepPath(APP_ROOT));
#else
// Initialize the editor and watch for changes
spZep = std::make_shared<ZepWrapper>(
fs::current_path(),
Zep::NVec2f(pixelScale.x, pixelScale.y),
[](std::shared_ptr<ZepMessage> spMessage) -> void { (void) spMessage; });
#endif
auto& display = spZep->GetEditor().GetDisplay();
auto pImFont = ImGui::GetIO().Fonts[0].Fonts[0];
auto pixelHeight = pImFont->FontSize;
display.SetFont(ZepTextType::UI, std::make_shared<ZepFont_ImGui>(display, pImFont, int(pixelHeight)));
display.SetFont(ZepTextType::Text, std::make_shared<ZepFont_ImGui>(display, pImFont, int(pixelHeight)));
display.SetFont(ZepTextType::Heading1, std::make_shared<ZepFont_ImGui>(display, pImFont, int(pixelHeight * 1.5)));
display.SetFont(ZepTextType::Heading2, std::make_shared<ZepFont_ImGui>(display, pImFont, int(pixelHeight * 1.25)));
display.SetFont(ZepTextType::Heading3, std::make_shared<ZepFont_ImGui>(display, pImFont, int(pixelHeight * 1.125)));
}
void zep_update()
{
if (spZep)
{
spZep->GetEditor().RefreshRequired();
}
}
void zep_destroy() { spZep.reset(); }
ZepEditor& zep_get_editor() { return spZep->GetEditor(); }
void zep_load(const Zep::ZepPath& file)
{
#ifndef ZEP_CONSOLE
auto pBuffer = zep_get_editor().InitWithFileOrDir(file);
(void)pBuffer;
#endif
}
void zep_show(const Zep::NVec2i& displaySize)
{
(void)displaySize;
// bool show = true;
#ifdef ZEP_CONSOLE
spZep->Draw("Console", &show, ImVec4(0, 0, 500, 400), true);
spZep->AddLog("Hello!");
#else
// ImGui::SetNextWindowSize(ImVec2(displaySize.x, displaySize.y), ImGuiCond_FirstUseEver);
// if (!ImGui::Begin("Zep", &show, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_MenuBar))
// {
// ImGui::End();
// return;
// }
auto min = ImGui::GetCursorScreenPos();
auto max = ImGui::GetContentRegionAvail();
if (max.x <= 0)
max.x = 1;
if (max.y <= 0)
max.y = 1;
ImGui::InvisibleButton("ZepContainer", max);
// Fill the window
max.x = min.x + max.x;
max.y = min.y + max.y;
spZep->zepEditor.SetDisplayRegion(Zep::NVec2f(min.x, min.y), Zep::NVec2f(max.x, max.y));
spZep->zepEditor.Display();
bool zep_focused = ImGui::IsWindowFocused();
if (zep_focused)
{
spZep->zepEditor.HandleInput();
}
// TODO: A Better solution for this; I think the audio graph is creating a new window and stealing focus
static int focus_count = 0;
if (focus_count++ < 2)
{
ImGui::SetWindowFocus();
}
// ImGui::End();
#endif
}

View File

@ -0,0 +1,11 @@
#pragma once
#include <zep/editor.h>
// Helpers to create zep editor
Zep::ZepEditor& zep_get_editor();
void zep_init(const Zep::NVec2f& pixelScale);
void zep_update();
void zep_show(const Zep::NVec2i& displaySize);
void zep_destroy();
void zep_load(const Zep::ZepPath& file);

View File

@ -0,0 +1,90 @@
#include "Manager.h"
#include "3rd/json.hpp"
#include <boost/algorithm/string.hpp>
#include <fstream>
namespace solidity::ui::project
{
void Manager::openProject(std::string const& _arguments)
{
auto projectIterator = std::find(m_historicalProjects.begin(), m_historicalProjects.end(), _arguments);
if (projectIterator != m_historicalProjects.end())
m_historicalProjects.erase(projectIterator);
m_historicalProjects.emplace_front(_arguments);
m_openedProjects.emplace_back(std::make_unique<solidity::ui::project::Project>(_arguments));
}
Manager::ProjectCache Manager::history(int _count /*=-1*/, std::string const& _search /*=""*/) const
{
Manager::ProjectCache result;
std::vector<std::string> words;
boost::split(words, _search, [](char c) { return c == ' '; });
for (auto const& project: m_historicalProjects)
{
bool containsAll = true;
for (auto const& word: words)
if (project.find(word) == std::string::npos)
containsAll = false;
if (containsAll)
result.emplace_back(project);
}
if (_count != -1 && result.size() > static_cast<size_t>(_count))
result.erase(result.begin() + _count, result.begin() + static_cast<int>(result.size()));
return result;
}
Manager::Projects const& Manager::projects() const { return m_openedProjects; }
void Manager::load(std::string const& _filename)
{
m_historicalProjects.clear();
m_openedProjects.clear();
nlohmann::json json;
try
{
std::ifstream f(_filename);
json = nlohmann::json::parse(f);
for (auto const& item: json["history"])
m_historicalProjects.emplace_back(item);
}
catch (...)
{
}
}
void Manager::save(std::string const& _filename)
{
nlohmann::json json;
nlohmann::json& historicalProjects = json["history"];
for (const auto& project: history())
historicalProjects.push_back(project);
try
{
std::ofstream o(_filename);
o << std::setw(4) << json << std::endl;
}
catch (...)
{
}
}
void Manager::render()
{
static solidity::ui::project::Project* lastFocusedProject{nullptr};
bool projectOpened = false;
for (auto&& project: m_openedProjects)
{
if (project->opened())
projectOpened = true;
if (project->render())
lastFocusedProject = project.get();
}
if (projectOpened == false)
lastFocusedProject = nullptr;
if (lastFocusedProject)
lastFocusedProject->renderProjectMenu();
}
} // namespace solidity::ui::project

View File

@ -0,0 +1,39 @@
#pragma once
#include "Project.h"
#include "Testcases.h"
#include <memory>
#include <string>
namespace solidity::ui::project
{
class Manager
{
public:
typedef std::vector<std::unique_ptr<solidity::ui::project::Project>> Projects;
typedef std::deque<std::string> ProjectCache;
static Manager& Instance()
{
static Manager manager;
return manager;
}
void openProject(std::string const& _arguments);
[[nodiscard]] ProjectCache history(int _count = -1, std::string const& _search = "") const;
[[nodiscard]] Projects const& projects() const;
void render();
void load(std::string const& _filename);
void save(std::string const& _filename);
Testcases& testcases() { return m_testcases; }
private:
Projects m_openedProjects;
ProjectCache m_historicalProjects;
Testcases m_testcases;
};
} // namespace solidity::ui::project

View File

@ -0,0 +1,58 @@
#include "Project.h"
#include "Editor.h"
namespace solidity::ui::project
{
void Project::initialize()
{
ImGuiIO& io = ImGui::GetIO();
ImGui::SetWindowPos(
{ImGui::GetTextLineHeightWithSpacing() + ImGui::GetTextLineHeightWithSpacing() * 2,
ImGui::GetTextLineHeightWithSpacing() * 2 + ImGui::GetTextLineHeightWithSpacing() * 2});
ImGui::SetWindowSize({io.DisplaySize.x / 2, io.DisplaySize.y / 2});
zep_init(Zep::NVec2f(1.0f, 1.0f));
zep_load(Zep::ZepPath(CMAKE_SOURCE_DIR) / "LICENSE.txt");
}
void Project::renderProjectMenu()
{
if (ImGui::BeginMainMenuBar())
{
if (ImGui::BeginMenu("Project"))
{
if (ImGui::BeginMenu("Compiler Options"))
{
m_options_ui->render();
ImGui::EndMenu();
}
ImGui::EndMenu();
}
ImGui::EndMainMenuBar();
}
}
bool Project::render()
{
bool focused = false;
if (m_opened)
{
if (ImGui::Begin(arguments().c_str(), &m_opened))
{
if (!m_initialized)
{
initialize();
m_initialized = true;
}
focused = ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows);
zep_update();
static Zep::NVec2i size = Zep::NVec2i(640, 480);
zep_show(size);
}
ImGui::End();
}
return focused;
}
} // namespace solidity::ui::project

View File

@ -0,0 +1,38 @@
#pragma once
#include "ui/CommandLineOptions.h"
#include <imgui.h>
#include <string>
#include <utility>
namespace solidity::ui::project
{
class Project
{
public:
explicit Project(std::string _arguments): m_arguments(std::move(_arguments))
{
m_options_ui = std::make_unique<solidity::ui::CommandLineOptions>(m_options);
}
[[nodiscard]] std::string const& arguments() const { return m_arguments; }
bool render();
void renderProjectMenu();
[[nodiscard]] bool opened() const { return m_opened; }
private:
void initialize();
bool m_initialized{false};
bool m_opened{true};
std::string m_arguments;
solidity::frontend::CommandLineOptions m_options;
std::unique_ptr<solidity::ui::CommandLineOptions> m_options_ui;
};
} // namespace solidity::ui::project

View File

@ -0,0 +1,121 @@
#include "Testcases.h"
#include "Manager.h"
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <filesystem>
#include <iostream>
namespace solidity::ui::project
{
Testcases::Testcases()
{
memset(m_search, 0, sizeof(m_search));
std::filesystem::recursive_directory_iterator dir(
std::filesystem::path(CMAKE_SOURCE_DIR "/test/libsolidity/semanticTests"));
for (auto&& i: dir)
{
if (!is_directory(i))
{
std::string path{i.path().parent_path().generic_string()};
boost::replace_all(path, CMAKE_SOURCE_DIR "/test/libsolidity/semanticTests/", "");
boost::replace_all(path, CMAKE_SOURCE_DIR "/test/libsolidity/semanticTests", "");
m_testcases[path].insert(i.path());
}
}
}
std::string Testcases::TrimMenuItem(std::string const& _string, size_t _maxLength)
{
std::string result{_string};
if (_string.length() > _maxLength)
result = _string.substr(0, (_maxLength / 2)) + ".."
+ _string.substr(_string.length() - (_maxLength / 2), _string.length());
return result;
}
void Testcases::renderMenuItems(std::string const& _parent)
{
(void) _parent;
for (auto&& i: m_testcases)
{
if (boost::starts_with(i.first, _parent + "/"))
{
std::string last(i.first.substr(_parent.length() + 1));
if (ImGui::BeginMenu(last.c_str()))
{
renderMenuItems(i.first);
ImGui::EndMenu();
}
}
}
for (auto&& i: m_testcases)
if (i.first == _parent)
{
for (auto&& file: i.second)
{
std::string entry = std::filesystem::path(file).filename().generic_string();
if (ImGui::MenuItem(TrimMenuItem(entry, 32).c_str()))
project::Manager::Instance().openProject(file);
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
ImGui::SetTooltip("%s", file.c_str());
}
}
}
void Testcases::renderMenuItems()
{
ImGui::InputTextWithHint(
"##1", "<enter text to search test-case>", m_search, sizeof(m_search), ImGuiInputTextFlags_AutoSelectAll);
std::string search(m_search);
if (!search.empty())
{
for (auto&& i: m_testcases)
for (auto&& file: i.second)
{
std::vector<std::string> words;
boost::split(words, boost::to_lower_copy(search), [](char c) { return c == ' '; });
bool containsAll = true;
for (auto const& word: words)
if (boost::to_lower_copy(std::filesystem::path(file).generic_string()).find(word)
== std::string::npos)
containsAll = false;
if (containsAll)
{
std::string path{std::filesystem::path(file)};
boost::replace_all(path, CMAKE_SOURCE_DIR "/test/libsolidity/semanticTests/", "");
boost::replace_all(path, CMAKE_SOURCE_DIR "/test/libsolidity/semanticTests", "");
if (ImGui::MenuItem(TrimMenuItem(path, 128).c_str()))
{
memset(m_search, 0, sizeof(m_search));
project::Manager::Instance().openProject(file);
}
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
ImGui::SetTooltip("%s", path.c_str());
}
}
}
else
{
for (auto&& i: m_testcases)
if (!i.first.empty() && i.first.find("/") == std::string::npos && ImGui::BeginMenu(i.first.c_str()))
{
renderMenuItems(i.first);
ImGui::EndMenu();
}
for (auto&& i: m_testcases)
if (i.first.empty())
for (auto&& file: i.second)
{
std::string entry = std::filesystem::path(file).filename().generic_string();
if (ImGui::MenuItem(TrimMenuItem(entry, 32).c_str()))
project::Manager::Instance().openProject(file);
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
ImGui::SetTooltip("%s", entry.c_str());
}
}
}
} // namespace solidity::ui::project

View File

@ -0,0 +1,23 @@
#pragma once
#include <string>
#include <map>
#include <set>
namespace solidity::ui::project
{
class Testcases
{
public:
Testcases();
void renderMenuItems();
private:
void renderMenuItems(std::string const& _parent);
static std::string TrimMenuItem(std::string const& _string, size_t _maxLength);
char m_search[128]{};
std::map<std::string, std::set<std::string>> m_testcases;
};
}

View File

@ -0,0 +1,387 @@
#pragma once
#include <imgui.h>
#include "solc/CommandLineParser.h"
#include <boost/algorithm/string/case_conv.hpp>
namespace solidity::ui
{
class CommandLineOptions
{
public:
explicit CommandLineOptions(solidity::frontend::CommandLineOptions& _options): m_options(_options) {}
void render(
std::function<bool(const char*, bool)> _begin = ImGui::BeginMenu,
std::function<void(void)> _end = ImGui::EndMenu)
{
// struct
// {
// InputMode mode = InputMode::Compiler;
// std::set<boost::filesystem::path> paths;
// std::vector<ImportRemapper::Remapping> remappings;
// bool addStdin = false;
// boost::filesystem::path basePath = "";
// std::vector<boost::filesystem::path> includePaths;
// FileReader::FileSystemPathSet allowedDirectories;
// bool ignoreMissingFiles = false;
// bool errorRecovery = false;
// } input;
if (_begin("Input", true))
{
std::string selection;
static const char* items[] = {
"License",
"Version",
"Compiler",
"Compiler With AST Import",
"Standard JSON",
"Linker",
"Assembler",
"Language Server",
};
ImGui::Combo("Input Mode", (int*) (&m_options.input.mode), items, IM_ARRAYSIZE(items), 4);
ImGui::Checkbox("Add STDIN", &m_options.input.addStdin);
ImGui::SameLine();
ImGui::Checkbox("Ignore Missing Files", &m_options.input.ignoreMissingFiles);
ImGui::SameLine();
ImGui::Checkbox("Error Recovery", &m_options.input.errorRecovery);
char basePath[1024];
memset(basePath, 0, sizeof(basePath));
memcpy(basePath, m_options.input.basePath.string().c_str(), m_options.input.basePath.string().length());
if (ImGui::InputText("Base Path", basePath, sizeof(basePath)))
{
m_options.input.basePath = std::string(basePath);
}
_end();
}
// struct
// {
// boost::filesystem::path dir;
// bool overwriteFiles = false;
// langutil::EVMVersion evmVersion;
// bool viaIR = false;
// RevertStrings revertStrings = RevertStrings::Default;
// std::optional<langutil::DebugInfoSelection> debugInfoSelection;
// CompilerStack::State stopAfter = CompilerStack::State::CompilationSuccessful;
// } output;
if (_begin("Output", true))
{
char directory[1024];
memset(directory, 0, sizeof(directory));
memcpy(directory, m_options.output.dir.string().c_str(), m_options.output.dir.string().length());
if (ImGui::InputText("Directory", directory, sizeof(directory)))
m_options.output.dir = std::string(directory);
static std::vector<solidity::langutil::EVMVersion> evm_versions{
solidity::langutil::EVMVersion::homestead(),
solidity::langutil::EVMVersion::tangerineWhistle(),
solidity::langutil::EVMVersion::spuriousDragon(),
solidity::langutil::EVMVersion::byzantium(),
solidity::langutil::EVMVersion::constantinople(),
solidity::langutil::EVMVersion::petersburg(),
solidity::langutil::EVMVersion::istanbul(),
solidity::langutil::EVMVersion::berlin(),
solidity::langutil::EVMVersion::london(),
};
static const char* evm_versions_text[] = {
"Homestead",
"Tangerine Whistle",
"SpuriousDragon",
"Byzantium",
"Constantinople",
"Petersburg",
"Istanbul",
"Berlin",
"London",
};
int evm_version_index = -1;
int evm_version_current_index = 0;
for (auto const& version: evm_versions)
{
if (version.name() == m_options.output.evmVersion.name())
evm_version_index = evm_version_current_index;
++evm_version_current_index;
}
if (ImGui::Combo("EVM Version", &evm_version_index, evm_versions_text, IM_ARRAYSIZE(evm_versions_text), 9))
m_options.output.evmVersion = solidity::langutil::EVMVersion::fromString(
evm_versions[static_cast<unsigned int>(evm_version_index)].name())
.value();
static const char* revert_strings_items[] = {"Default", "Strip", "Debug", "Verbose Debug"};
int revert_strings_index = (int) m_options.output.revertStrings;
if (ImGui::Combo(
"Revert Strings",
&revert_strings_index,
revert_strings_items,
IM_ARRAYSIZE(revert_strings_items),
4))
m_options.output.revertStrings = static_cast<solidity::frontend::RevertStrings>(revert_strings_index);
ImGui::Checkbox("Overwrite Files", &m_options.output.overwriteFiles);
ImGui::SameLine();
ImGui::Checkbox("Via IR", &m_options.output.viaIR);
if (m_options.output.debugInfoSelection.has_value())
{
ImGui::Text("Debug Info Selection");
ImGui::Checkbox("Location", &m_options.output.debugInfoSelection->location);
ImGui::SameLine();
ImGui::Checkbox("Snippet", &m_options.output.debugInfoSelection->snippet);
ImGui::SameLine();
ImGui::Checkbox("AST ID", &m_options.output.debugInfoSelection->astID);
}
static const char* compiler_states_text[]
= {"Empty",
"Sources Set",
"Parsed",
"Parsed And Imported",
"Analysis Performed",
"Compilation Successful"};
int compiler_states_index = (int) m_options.output.stopAfter;
if (ImGui::Combo(
"Stop After", &revert_strings_index, compiler_states_text, IM_ARRAYSIZE(compiler_states_text), 4))
m_options.output.stopAfter
= static_cast<solidity::frontend::CompilerStack::State>(compiler_states_index);
_end();
}
// struct
// {
// yul::YulStack::Machine targetMachine = yul::YulStack::Machine::EVM;
// yul::YulStack::Language inputLanguage = yul::YulStack::Language::StrictAssembly;
// } assembly;
if (_begin("Assembly", true))
{
// solidity::yul::YulStack::Machine
static const char* input_language_text[] = {"Yul", "Assembly", "Strict Assembly", "EWASM"};
int input_language_index = (int) m_options.assembly.inputLanguage;
if (ImGui::Combo(
"Input Language", &input_language_index, input_language_text, IM_ARRAYSIZE(input_language_text), 4))
m_options.assembly.inputLanguage = static_cast<solidity::yul::YulStack::Language>(input_language_index);
static const char* target_machine_text[] = {"EVM", "EWASM"};
int target_machine_index = (int) m_options.assembly.targetMachine;
if (ImGui::Combo(
"Target Machine", &target_machine_index, target_machine_text, IM_ARRAYSIZE(target_machine_text), 4))
m_options.assembly.targetMachine = static_cast<solidity::yul::YulStack::Machine>(target_machine_index);
_end();
}
// struct
// {
// std::map<std::string, util::h160> libraries; // library name -> address
// } linker;
if (_begin("Linker", true))
{
for (auto& library: m_options.linker.libraries)
{
char value[128];
memset(&value, 0, sizeof(value));
memcpy(value, library.second.hex().c_str(), library.second.hex().length());
ImGui::PushItemWidth(700);
if (ImGui::InputText(library.first.c_str(), value, sizeof(value)))
try
{
library.second = solidity::util::h160(
std::string(value),
solidity::util::h160::ConstructFromStringType::FromHex,
solidity::util::h160::ConstructFromHashType::AlignRight);
}
catch (...)
{
library.second = solidity::util::h160();
}
}
_end();
}
// struct
// {
// util::JsonFormat json;
// std::optional<bool> coloredOutput;
// bool withErrorIds = false;
// } formatting;
if (_begin("Formatting", true))
{
static const char* json_formatting_text[] = {"Compact", "Pretty"};
int json_formatting_index = (int) m_options.formatting.json.format;
if (ImGui::
Combo("JSON", &json_formatting_index, json_formatting_text, IM_ARRAYSIZE(json_formatting_text), 4))
m_options.formatting.json.format
= static_cast<solidity::util::JsonFormat::Format>(json_formatting_index);
ImGui::Checkbox("With Error IDs", &m_options.formatting.withErrorIds);
if (m_options.formatting.coloredOutput.has_value())
{
ImGui::SameLine();
ImGui::Checkbox("Colored Output", &m_options.formatting.coloredOutput.value());
}
_end();
}
// struct
// {
// CompilerOutputs outputs;
// bool estimateGas = false;
// std::optional<CombinedJsonRequests> combinedJsonRequests;
// } compiler;
if (_begin("Compiler", true))
{
ImGui::Checkbox("Estimate Gas", &m_options.compiler.estimateGas);
ImGui::Text("Outputs");
int current = 0;
for (auto& i: solidity::frontend::CompilerOutputs::componentMap())
{
bool checkbox = i.second;
if (current % 2 == 1)
ImGui::SameLine();
ImGui::Checkbox(i.first.c_str(), &checkbox);
++current;
}
ImGui::Text("Combined JSON Requests");
current = 0;
for (auto& i: solidity::frontend::CombinedJsonRequests::componentMap())
{
bool checkbox = i.second;
if (current % 2 == 1)
ImGui::SameLine();
ImGui::Checkbox(i.first.c_str(), &checkbox);
++current;
}
_end();
}
// struct
// {
// CompilerStack::MetadataHash hash = CompilerStack::MetadataHash::IPFS;
// bool literalSources = false;
// } metadata;
if (_begin("Metadata", true))
{
static const char* metadata_hash_type[] = {"IPFS", "BZZR1", "None"};
int metadata_hash_type_selection = (int) m_options.metadata.hash;
if (ImGui::Combo(
"Metadata Hash Type",
&metadata_hash_type_selection,
metadata_hash_type,
IM_ARRAYSIZE(metadata_hash_type),
4))
m_options.metadata.hash
= static_cast<solidity::frontend::CompilerStack::MetadataHash>(metadata_hash_type_selection);
ImGui::Checkbox("Literal Sources", &m_options.metadata.literalSources);
_end();
}
// struct
// {
// bool enabled = false;
// std::optional<unsigned> expectedExecutionsPerDeployment;
// bool noOptimizeYul = false;
// std::optional<std::string> yulSteps;
// } optimizer;
if (_begin("Optimizer", true))
{
ImGui::Checkbox("Enabled", &m_options.optimizer.enabled);
ImGui::SameLine();
ImGui::Checkbox("No Optimize YUL", &m_options.optimizer.noOptimizeYul);
if (m_options.optimizer.expectedExecutionsPerDeployment.has_value())
{
ImGui::InputInt(
"Expected Executions Per Deployment",
(int*) &m_options.optimizer.expectedExecutionsPerDeployment.value());
if (static_cast<int>(m_options.optimizer.expectedExecutionsPerDeployment.value()) < 0)
m_options.optimizer.expectedExecutionsPerDeployment = 0;
}
if (m_options.optimizer.yulSteps.has_value())
{
char input[1024];
memset(input, 0x00, sizeof(input));
memcpy(
input, m_options.optimizer.yulSteps.value().c_str(), m_options.optimizer.yulSteps.value().length());
if (ImGui::InputText("YUL Steps", input, sizeof(input)))
m_options.optimizer.yulSteps = std::string(input);
}
_end();
}
// struct
// {
// bool initialize = false;
// ModelCheckerSettings settings;
// } modelChecker;
if (_begin("Model Checker", true))
{
ImGui::Checkbox("Initialize", &m_options.modelChecker.initialize);
ImGui::Checkbox("Div Mod No Slacks", &m_options.modelChecker.settings.divModNoSlacks);
ImGui::SameLine();
ImGui::Checkbox("Show Unproved", &m_options.modelChecker.settings.showUnproved);
static const char* engine_text[] = {"All", "BMC", "CHC", "None"};
int engine_index = -1;
if (m_options.modelChecker.settings.engine.bmc == true
&& m_options.modelChecker.settings.engine.chc == true)
engine_index = 0;
else if (
m_options.modelChecker.settings.engine.bmc == true
&& m_options.modelChecker.settings.engine.chc == false)
engine_index = 1;
else if (
m_options.modelChecker.settings.engine.bmc == false
&& m_options.modelChecker.settings.engine.chc == true)
engine_index = 2;
else if (
m_options.modelChecker.settings.engine.bmc == false
&& m_options.modelChecker.settings.engine.chc == false)
engine_index = 3;
if (ImGui::Combo("Engine", &engine_index, engine_text, IM_ARRAYSIZE(engine_text), 4))
m_options.modelChecker.settings.engine
= solidity::frontend::ModelCheckerEngine::fromString(
boost::to_lower_copy(std::string(engine_text[engine_index])))
.value();
// Contract, Reentrancy, all, default
static const char* invariants_text[] = {"All", "Contract", "Reentrancy", "Default"};
int invariants_selection = -1;
if (m_options.modelChecker.settings.invariants == solidity::frontend::ModelCheckerInvariants::All())
invariants_selection = 0;
else if (
m_options.modelChecker.settings.invariants
== solidity::frontend::ModelCheckerInvariants::fromString("contract"))
invariants_selection = 1;
else if (
m_options.modelChecker.settings.invariants
== solidity::frontend::ModelCheckerInvariants::fromString("reentrancy"))
invariants_selection = 2;
else if (
m_options.modelChecker.settings.invariants == solidity::frontend::ModelCheckerInvariants::Default())
invariants_selection = 3;
if (ImGui::Combo("Invariants", &invariants_selection, invariants_text, IM_ARRAYSIZE(invariants_text), 4))
m_options.modelChecker.settings.invariants
= solidity::frontend::ModelCheckerInvariants::fromString(
boost::to_lower_copy(std::string(invariants_text[invariants_selection])))
.value();
static const char* solver_text[]
= {"All",
"CVC4",
"SMTLIB2",
"Z3"}; // and "None", todo: ask leo about smtutil::SMTSolverChoice::fromString
int solver_index = -1;
if (m_options.modelChecker.settings.solvers.cvc4 == true
&& m_options.modelChecker.settings.solvers.smtlib2 == true
&& m_options.modelChecker.settings.solvers.z3 == true)
solver_index = 0;
else if (m_options.modelChecker.settings.solvers.cvc4 == true)
solver_index = 1;
else if (m_options.modelChecker.settings.solvers.smtlib2 == true)
solver_index = 2;
else if (m_options.modelChecker.settings.solvers.z3 == true)
solver_index = 3;
// todo: ask leo
// else if (m_options.modelChecker.settings.solvers.cvc4 == false &&
// m_options.modelChecker.settings.solvers.smtlib2 == false && m_options.modelChecker.settings.solvers.z3
//== false) solver_index = 4;
if (ImGui::Combo("Solver", &solver_index, solver_text, IM_ARRAYSIZE(solver_text), 4))
m_options.modelChecker.settings.solvers
= solidity::smtutil::SMTSolverChoice::fromString(
boost::to_lower_copy(std::string(solver_text[solver_index])))
.value();
_end();
}
}
private:
solidity::frontend::CommandLineOptions& m_options;
};
} // namespace solidity::ui