openMSX
ImGuiSymbols.cc
Go to the documentation of this file.
1#include "ImGuiSymbols.hh"
2
3#include "ImGuiBreakPoints.hh"
4#include "ImGuiCpp.hh"
5#include "ImGuiManager.hh"
6#include "ImGuiOpenFile.hh"
7#include "ImGuiUtils.hh"
8#include "ImGuiWatchExpr.hh"
9
10#include "CliComm.hh"
11#include "File.hh"
12#include "Interpreter.hh"
13#include "MSXException.hh"
14#include "Reactor.hh"
15
16#include "enumerate.hh"
17#include "ranges.hh"
18#include "StringOp.hh"
19#include "stl.hh"
20#include "strCat.hh"
21#include "unreachable.hh"
22#include "xrange.hh"
23
24#include <imgui.h>
25
26#include <cassert>
27
28namespace openmsx {
29
31 : ImGuiPart(manager_)
32 , symbolManager(manager.getReactor().getSymbolManager())
33{
34 symbolManager.setObserver(this);
35}
36
38{
39 symbolManager.setObserver(nullptr);
40}
41
42void ImGuiSymbols::save(ImGuiTextBuffer& buf)
43{
44 savePersistent(buf, *this, persistentElements);
45 for (const auto& file : symbolManager.getFiles()) {
46 buf.appendf("symbolfile=%s\n", file.filename.c_str());
47 buf.appendf("symbolfiletype=%s\n", SymbolFile::toString(file.type).c_str());
48 }
49 for (const auto& [file, error, type] : fileError) {
50 buf.appendf("symbolfile=%s\n", file.c_str());
51 buf.appendf("symbolfiletype=%s\n", SymbolFile::toString(type).c_str());
52 }
53}
54
56{
57 symbolManager.removeAllFiles();
58 fileError.clear();
59}
60
61void ImGuiSymbols::loadLine(std::string_view name, zstring_view value)
62{
63 if (loadOnePersistent(name, value, *this, persistentElements)) {
64 // already handled
65 } else if (name == "symbolfile") {
66 fileError.emplace_back(std::string{value}, // filename
67 std::string{}, // error
69 } else if (name == "symbolfiletype") {
70 if (!fileError.empty()) {
71 fileError.back().type =
73 }
74 }
75}
76
78{
79 std::vector<FileInfo> tmp;
80 std::swap(tmp, fileError);
81 for (const auto& info : tmp) {
82 loadFile(info.filename, SymbolManager::LoadEmpty::ALLOWED, info.type);
83 }
84}
85
86void ImGuiSymbols::loadFile(const std::string& filename, SymbolManager::LoadEmpty loadEmpty, SymbolFile::Type type)
87{
88 auto& cliComm = manager.getCliComm();
89 auto it = ranges::find(fileError, filename, &FileInfo::filename);
90 try {
91 if (!symbolManager.reloadFile(filename, loadEmpty, type)) {
92 cliComm.printWarning("Symbol file \"", filename,
93 "\" doesn't contain any symbols");
94 }
95 if (it != fileError.end()) fileError.erase(it); // clear previous error
96 } catch (MSXException& e) {
97 cliComm.printWarning(
98 "Couldn't load symbol file \"", filename, "\": ", e.getMessage());
99 if (it != fileError.end()) {
100 it->error = e.getMessage(); // overwrite previous error
101 it->type = type;
102 } else {
103 fileError.emplace_back(filename, e.getMessage(), type); // set error
104 }
105 }
106}
107
108static void checkSort(const SymbolManager& manager, std::vector<SymbolRef>& symbols)
109{
110 auto* sortSpecs = ImGui::TableGetSortSpecs();
111 if (!sortSpecs->SpecsDirty) return;
112
113 sortSpecs->SpecsDirty = false;
114 assert(sortSpecs->SpecsCount == 1);
115 assert(sortSpecs->Specs);
116 assert(sortSpecs->Specs->SortOrder == 0);
117
118 switch (sortSpecs->Specs->ColumnIndex) {
119 case 0: // name
120 sortUpDown_String(symbols, sortSpecs, [&](const auto& sym) { return sym.name(manager); });
121 break;
122 case 1: // value
123 sortUpDown_T(symbols, sortSpecs, [&](const auto& sym) { return sym.value(manager); });
124 break;
125 case 2: // file
126 sortUpDown_String(symbols, sortSpecs, [&](const auto& sym) { return sym.file(manager); });
127 break;
128 default:
130 }
131}
132template<bool FILTER_FILE>
133static void drawTable(ImGuiManager& manager, const SymbolManager& symbolManager, std::vector<SymbolRef>& symbols, const std::string& file = {})
134{
135 assert(FILTER_FILE == !file.empty());
136
137 int flags = ImGuiTableFlags_RowBg |
138 ImGuiTableFlags_BordersV |
139 ImGuiTableFlags_BordersOuter |
140 ImGuiTableFlags_ContextMenuInBody |
141 ImGuiTableFlags_Resizable |
142 ImGuiTableFlags_Reorderable |
143 ImGuiTableFlags_Sortable |
144 ImGuiTableFlags_SizingStretchProp |
145 (FILTER_FILE ? ImGuiTableFlags_ScrollY : 0);
146 im::Table(file.c_str(), FILTER_FILE ? 2 : 3, flags, {0, 100}, [&]{
147 ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible
148 ImGui::TableSetupColumn("name");
149 ImGui::TableSetupColumn("value", ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed);
150 if (!FILTER_FILE) {
151 ImGui::TableSetupColumn("file");
152 }
153 ImGui::TableHeadersRow();
154 checkSort(symbolManager, symbols);
155
156 for (const auto& sym : symbols) {
157 if (FILTER_FILE && (sym.file(symbolManager) != file)) continue;
158
159 if (ImGui::TableNextColumn()) { // name
160 im::ScopedFont sf(manager.fontMono);
161 ImGui::TextUnformatted(sym.name(symbolManager));
162 }
163 if (ImGui::TableNextColumn()) { // value
164 im::ScopedFont sf(manager.fontMono);
165 ImGui::StrCat(hex_string<4>(sym.value(symbolManager)));
166 }
167 if (!FILTER_FILE && ImGui::TableNextColumn()) { // file
168 ImGui::TextUnformatted(sym.file(symbolManager));
169 }
170 }
171 });
172}
173
175{
176 if (!show) return;
177
178 ImGui::SetNextWindowSize(gl::vec2{24, 18} * ImGui::GetFontSize(), ImGuiCond_FirstUseEver);
179 im::Window("Symbol Manager", &show, [&]{
180 if (ImGui::Button("Load symbol file...")) {
181 manager.openFile->selectFile(
182 "Select symbol file",
184 [this](const std::string& filename) {
186 loadFile(filename, SymbolManager::LoadEmpty::NOT_ALLOWED, type);
187 });
188 }
189
190 im::TreeNode("Symbols per file", ImGuiTreeNodeFlags_DefaultOpen, [&]{
191 auto drawFile = [&](const FileInfo& info) {
192 im::StyleColor(!info.error.empty(), ImGuiCol_Text, getColor(imColor::ERROR), [&]{
193 auto title = strCat("File: ", info.filename);
194 im::TreeNode(title.c_str(), [&]{
195 if (!info.error.empty()) {
196 ImGui::TextUnformatted(info.error);
197 }
198 im::StyleColor(ImGuiCol_Text, getColor(imColor::TEXT), [&]{
199 if (ImGui::Button("Reload")) {
200 loadFile(info.filename, SymbolManager::LoadEmpty::NOT_ALLOWED, info.type);
201 }
202 ImGui::SameLine();
203 if (ImGui::Button("Remove")) {
204 symbolManager.removeFile(info.filename);
205 if (auto it = ranges::find(fileError, info.filename, &FileInfo::filename);
206 it != fileError.end()) {
207 fileError.erase(it);
208 }
209 }
210 drawTable<true>(manager, symbolManager, symbols, info.filename);
211 });
212 });
213 });
214 };
215
216 // make copy because cache may get dropped
217 auto infos = to_vector(view::transform(symbolManager.getFiles(), [](const auto& file) {
218 return FileInfo{file.filename, std::string{}, file.type};
219 }));
220 append(infos, fileError);
221 for (const auto& info : infos) {
222 drawFile(info);
223 }
224
225 });
226 im::TreeNode("All symbols", [&]{
227 if (ImGui::Button("Reload all")) {
228 auto tmp = to_vector(view::transform(symbolManager.getFiles(), [](const auto& file) {
229 return FileInfo{file.filename, std::string{}, file.type};
230 }));
231 append(tmp, std::move(fileError));
232 fileError.clear();
233 for (const auto& info : tmp) {
234 loadFile(info.filename, SymbolManager::LoadEmpty::NOT_ALLOWED, info.type);
235 }
236 }
237 ImGui::SameLine();
238 if (ImGui::Button("Remove all")) {
239 symbolManager.removeAllFiles();
240 fileError.clear();
241 }
242 drawTable<false>(manager, symbolManager, symbols);
243 });
244 });
245}
246
247void ImGuiSymbols::notifySymbolsChanged()
248{
249 symbols.clear();
250 for (const auto& [fileIdx, file] : enumerate(symbolManager.getFiles())) {
251 for (auto symbolIdx : xrange(file.symbols.size())) {
252 //symbols.emplace_back(narrow<unsigned>(fileIdx),
253 // narrow<unsigned>(symbolIdx));
254 // clang workaround
255 symbols.push_back(SymbolRef{narrow<unsigned>(fileIdx),
256 narrow<unsigned>(symbolIdx)});
257 }
258 }
259
260 manager.breakPoints->refreshSymbols();
261 manager.watchExpr->refreshSymbols();
262}
263
264} // namespace openmsx
std::unique_ptr< ImGuiOpenFile > openFile
static std::string getLastFilter()
ImGuiManager & manager
Definition ImGuiPart.hh:30
void loadLine(std::string_view name, zstring_view value) override
void save(ImGuiTextBuffer &buf) override
void loadStart() override
void loadEnd() override
void paint(MSXMotherBoard *motherBoard) override
ImGuiSymbols(ImGuiManager &manager)
const auto & getFiles() const
bool reloadFile(const std::string &filename, LoadEmpty loadEmpty, SymbolFile::Type type)
static std::string getFileFilters()
static SymbolFile::Type getTypeForFilter(std::string_view filter)
void setObserver(SymbolObserver *observer_)
Like std::string_view, but with the extra guarantee that it refers to a zero-terminated string.
constexpr const char * c_str() const
constexpr auto enumerate(Iterable &&iterable)
Heavily inspired by Nathan Reed's blog post: Python-Like enumerate() In C++17 http://reedbeta....
Definition enumerate.hh:28
void StrCat(Ts &&...ts)
Definition ImGuiUtils.hh:43
void TextUnformatted(const std::string &str)
Definition ImGuiUtils.hh:24
constexpr double e
Definition Math.hh:21
void Table(const char *str_id, int column, ImGuiTableFlags flags, const ImVec2 &outer_size, float inner_width, std::invocable<> auto next)
Definition ImGuiCpp.hh:459
void Window(const char *name, bool *p_open, ImGuiWindowFlags flags, std::invocable<> auto next)
Definition ImGuiCpp.hh:63
bool TreeNode(const char *label, ImGuiTreeNodeFlags flags, std::invocable<> auto next)
Definition ImGuiCpp.hh:306
void StyleColor(bool active, Args &&...args)
Definition ImGuiCpp.hh:175
This file implemented 3 utility functions:
Definition Autofire.cc:11
bool loadOnePersistent(std::string_view name, zstring_view value, C &c, const std::tuple< Elements... > &tup)
void sortUpDown_String(Range &range, const ImGuiTableSortSpecs *sortSpecs, Projection proj)
void savePersistent(ImGuiTextBuffer &buf, C &c, const std::tuple< Elements... > &tup)
void sortUpDown_T(Range &range, const ImGuiTableSortSpecs *sortSpecs, Projection proj)
ImU32 getColor(imColor col)
auto find(InputRange &&range, const T &value)
Definition ranges.hh:162
size_t size(std::string_view utf8)
constexpr auto transform(Range &&range, UnaryOp op)
Definition view.hh:520
auto to_vector(Range &&range) -> std::vector< detail::ToVectorType< T, decltype(std::begin(range))> >
Definition stl.hh:275
std::string strCat()
Definition strCat.hh:703
static std::optional< Type > parseType(std::string_view str)
static zstring_view toString(Type type)
#define UNREACHABLE
constexpr auto xrange(T e)
Definition xrange.hh:132