36 , symbolManager(manager.getReactor().getSymbolManager())
49 for (
const auto& file : symbolManager.
getFiles()) {
50 buf.appendf(
"symbolfile=%s\n", file.filename.c_str());
53 buf.appendf(
"slotsubslot=%d\n", *file.slot);
56 for (
const auto& [file, error, type, slot] : fileError) {
57 buf.appendf(
"symbolfile=%s\n", file.c_str());
60 buf.appendf(
"slotsubslot=%d\n", *slot);
75 }
else if (name ==
"symbolfile") {
76 fileError.emplace_back(std::string{value},
80 }
else if (name ==
"symbolfiletype") {
81 if (!fileError.empty()) {
82 fileError.back().type =
85 }
else if (name ==
"slotsubslot") {
86 if (!fileError.empty()) {
87 if (
auto slot = StringOp::stringTo<int>(value)) {
88 fileError.back().slot = slot;
96 std::vector<FileInfo> tmp;
97 std::swap(tmp, fileError);
98 for (
const auto& info : tmp) {
108 if (!symbolManager.
reloadFile(filename, loadEmpty, type, slot)) {
109 cliComm.printWarning(
"Symbol file \"", filename,
110 "\" doesn't contain any symbols");
112 if (it != fileError.end()) fileError.erase(it);
113 }
catch (MSXException& e) {
114 cliComm.printWarning(
115 "Couldn't load symbol file \"", filename,
"\": ",
e.getMessage());
116 if (it != fileError.end()) {
117 it->error =
e.getMessage();
120 fileError.emplace_back(filename,
e.getMessage(), type, slot);
125static bool isSlotExpanded(MSXMotherBoard* motherBoard,
int ps)
127 return motherBoard !=
nullptr ? motherBoard->getCPUInterface().isExpanded(ps) :
true;
130static std::string formatSlot(std::optional<uint8_t> slot, MSXMotherBoard* motherBoard =
nullptr)
132 if (!slot)
return "-";
133 int ps = (*slot >> 0) & 3;
134 int ss = (*slot >> 2) & 3;
135 return isSlotExpanded(motherBoard, ps) ?
strCat(ps,
'-', ss)
139static void checkSort(
const SymbolManager& manager, std::vector<SymbolRef>& symbols)
141 auto* sortSpecs = ImGui::TableGetSortSpecs();
142 if (!sortSpecs->SpecsDirty)
return;
144 sortSpecs->SpecsDirty =
false;
145 assert(sortSpecs->SpecsCount == 1);
146 assert(sortSpecs->Specs);
147 assert(sortSpecs->Specs->SortOrder == 0);
149 switch (sortSpecs->Specs->ColumnIndex) {
151 sortUpDown_String(symbols, sortSpecs, [&](
const auto& sym) {
return sym.name(manager); });
154 sortUpDown_T(symbols, sortSpecs, [&](
const auto& sym) {
return sym.value(manager); });
157 sortUpDown_String(symbols, sortSpecs, [&](
const auto& sym) {
return formatSlot(sym.slot(manager)); });
160 sortUpDown_T(symbols, sortSpecs, [&](
const auto& sym) {
return sym.segment(manager); });
163 sortUpDown_String(symbols, sortSpecs, [&](
const auto& sym) {
return sym.file(manager); });
170void ImGuiSymbols::drawContext(MSXMotherBoard* motherBoard,
const SymbolRef& sym)
172 if (ImGui::MenuItem(
"Show in Dissassembly",
nullptr,
nullptr, motherBoard !=
nullptr)) {
175 if (ImGui::MenuItem(
"Set breakpoint",
nullptr,
nullptr, motherBoard !=
nullptr)) {
177 if (
auto slot = sym.slot(symbolManager)) {
178 strAppend(cond,
"[pc_in_slot ", *slot & 3,
' ', (*slot >> 2) & 3);
179 if (
auto segment = sym.segment(symbolManager)) {
184 BreakPoint newBp(sym.value(symbolManager), TclObject(
"debug break"), TclObject(cond),
false);
185 auto& cpuInterface = motherBoard->getCPUInterface();
186 cpuInterface.insertBreakPoint(std::move(newBp));
190template<
bool FILTER_FILE>
191void ImGuiSymbols::drawTable(MSXMotherBoard* motherBoard,
const std::string& file)
193 assert(FILTER_FILE == !file.empty());
195 int flags = ImGuiTableFlags_RowBg |
196 ImGuiTableFlags_BordersV |
197 ImGuiTableFlags_BordersOuter |
198 ImGuiTableFlags_ContextMenuInBody |
199 ImGuiTableFlags_Resizable |
200 ImGuiTableFlags_Reorderable |
201 ImGuiTableFlags_Sortable |
202 ImGuiTableFlags_Hideable |
203 ImGuiTableFlags_SizingStretchProp |
204 (FILTER_FILE ? ImGuiTableFlags_ScrollY : 0);
205 im::Table(file.c_str(), (FILTER_FILE ? 4 : 5), flags, {0, 100}, [&]{
206 ImGui::TableSetupScrollFreeze(0, 1);
207 ImGui::TableSetupColumn(
"name", ImGuiTableColumnFlags_NoHide);
208 ImGui::TableSetupColumn(
"value", ImGuiTableColumnFlags_NoHide | ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed);
209 ImGui::TableSetupColumn(
"slot", ImGuiTableColumnFlags_DefaultHide);
210 ImGui::TableSetupColumn(
"segment", ImGuiTableColumnFlags_DefaultHide);
212 ImGui::TableSetupColumn(
"file");
214 ImGui::TableHeadersRow();
215 checkSort(symbolManager, symbols);
217 for (
const auto& sym : symbols) {
218 if (FILTER_FILE && (sym.file(symbolManager) != file))
continue;
220 if (ImGui::TableNextColumn()) {
222 const auto& symName = sym.name(symbolManager);
223 ImGui::Selectable(symName.c_str(),
false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap);
224 auto symNameMenu =
strCat(
"symbol-manager##", symName);
225 if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
226 ImGui::OpenPopup(symNameMenu.c_str());
228 im::Popup(symNameMenu.c_str(), [&]{ drawContext(motherBoard, sym); });
230 if (ImGui::TableNextColumn()) {
234 if (ImGui::TableNextColumn()) {
238 if (ImGui::TableNextColumn()) {
242 if (!FILTER_FILE && ImGui::TableNextColumn()) {
253 const auto& style = ImGui::GetStyle();
254 ImGui::SetNextWindowSize(
gl::vec2{24, 18} * ImGui::GetFontSize(), ImGuiCond_FirstUseEver);
256 if (ImGui::Button(
"Load symbol file...")) {
258 "Select symbol file",
260 [
this](
const std::string& filename) {
266 im::TreeNode(
"Symbols per file", ImGuiTreeNodeFlags_DefaultOpen, [&]{
267 std::optional<FileInfo> reloadAction;
268 std::string removeAction;
269 auto drawFile = [&](
const std::string& filename, std::string_view error,
SymbolFile::Type type, std::optional<int> slot) {
270 bool hasError = !error.empty();
271 auto* file = symbolManager.
findFile(filename);
272 assert((file !=
nullptr) ^ hasError);
274 auto title =
tmpStrCat(
"File: ", filename);
277 ImGui::TextUnformatted(error);
281 auto arrowSize = ImGui::GetFrameHeight();
282 auto extra = arrowSize + 2.0f * style.FramePadding.x;
284 ImGui::AlignTextToFramePadding();
286 auto preview = formatSlot(file->slot, motherBoard);
289 auto setSlot = [&](std::optional<uint8_t> newSlot) {
290 file->slot = newSlot;
291 for (auto& symbol : file->getSymbols()) {
292 symbol.slot = newSlot;
296 if (ImGui::Selectable(
"-", !file->slot)) {
300 for (uint8_t ps = 0; ps < 4; ++ps) {
301 if (isSlotExpanded(motherBoard, ps)) {
302 for (uint8_t ss = 0; ss < 4; ++ss) {
304 int psSs = (ss << 2) + ps;
305 if (ImGui::Selectable(slotInfo.c_str(), psSs == file->slot)) {
310 if (ImGui::Selectable(
tmpStrCat(ps).c_str(), file->slot && ps == file->slot)) {
319 if (ImGui::Button(
"Reload")) {
320 reloadAction.emplace(filename, std::string{}, type, slot);
323 if (ImGui::Button(
"Remove")) {
324 removeAction = filename;
327 drawTable<true>(motherBoard, filename);
334 for (
const auto& file : symbolManager.
getFiles()) {
335 drawFile(file.filename, {}, file.type, file.slot);
337 for (
const auto& info : fileError) {
338 drawFile(info.filename, info.error, info.type, info.slot);
344 reloadAction->type, reloadAction->slot);
346 if (!removeAction.empty()) {
349 it != fileError.end()) {
355 if (ImGui::Button(
"Reload all")) {
357 return FileInfo{file.filename, std::string{}, file.type, file.slot};
359 append(tmp, std::move(fileError));
361 for (
const auto& info : tmp) {
366 if (ImGui::Button(
"Remove all")) {
367 symbolManager.removeAllFiles();
370 drawTable<false>(motherBoard);
375void ImGuiSymbols::notifySymbolsChanged()
378 for (
const auto& [fileIdx, file] :
enumerate(symbolManager.getFiles())) {
379 for (
auto symbolIdx :
xrange(file.symbols.
size())) {
383 symbols.push_back(SymbolRef{narrow<unsigned>(fileIdx),
384 narrow<unsigned>(symbolIdx)});
388 manager.breakPoints->refreshSymbols();
389 manager.watchExpr->refreshSymbols();
const char * c_str() const
std::unique_ptr< ImGuiOpenFile > openFile
std::unique_ptr< ImGuiDebugger > debugger
static std::string getLastFilter()
void loadLine(std::string_view name, zstring_view value) override
void save(ImGuiTextBuffer &buf) override
void loadStart() override
void paint(MSXMotherBoard *motherBoard) override
ImGuiSymbols(ImGuiManager &manager)
const auto & getFiles() const
static std::string getFileFilters()
void removeFile(std::string_view filename)
bool reloadFile(const std::string &filename, LoadEmpty loadEmpty, SymbolFile::Type type, std::optional< uint8_t > slot={})
static SymbolFile::Type getTypeForFilter(std::string_view filter)
SymbolFile * findFile(std::string_view filename)
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....
auto CalcTextSize(std::string_view str)
void TextUnformatted(const std::string &str)
void Table(const char *str_id, int column, ImGuiTableFlags flags, const ImVec2 &outer_size, float inner_width, std::invocable<> auto next)
void Window(const char *name, bool *p_open, ImGuiWindowFlags flags, std::invocable<> auto next)
bool TreeNode(const char *label, ImGuiTreeNodeFlags flags, std::invocable<> auto next)
void Combo(const char *label, const char *preview_value, ImGuiComboFlags flags, std::invocable<> auto next)
void StyleColor(bool active, Args &&...args)
void Popup(const char *str_id, ImGuiWindowFlags flags, std::invocable<> auto next)
This file implemented 3 utility functions:
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)
size_t size(std::string_view utf8)
constexpr auto transform(Range &&range, UnaryOp op)
auto to_vector(Range &&range) -> std::vector< detail::ToVectorType< T, decltype(std::begin(range))> >
TemporaryString tmpStrCat(Ts &&... ts)
void strAppend(std::string &result, Ts &&...ts)
static std::optional< Type > parseType(std::string_view str)
static zstring_view toString(Type type)
constexpr auto xrange(T e)