1 #pragma once 2 3 #include "../../plugins/assembler/printer.h" 4 #include "listingdocument.h" 5 6 #define REDASM_WORD_REGEX "([\\w\\$_\\.]+)" 7 8 namespace REDasm { 9 10 struct RendererFormat 11 { 12 size_t start, end; // [start, end] 13 std::string fgstyle, bgstyle; 14 lengthRendererFormat15 inline size_t length() const { 16 if((start == REDasm::npos) || (end == REDasm::npos)) 17 return 0; 18 19 return start <= end ? (end - start + 1) : 0; 20 } 21 emptyRendererFormat22 inline bool empty() const { return this->length() == 0; } containsRendererFormat23 inline bool contains(size_t pos) const { return (pos >= start) && (pos <= end); } equalsRendererFormat24 inline bool equals(size_t start, size_t end) const { return (start == this->start) && (end == this->end); } 25 }; 26 27 struct RendererLine 28 { userdataRendererLine29 RendererLine(bool ignoreflags = false): userdata(nullptr), documentindex(0), index(0), highlighted(false), ignoreflags(ignoreflags) { } 30 31 void* userdata; 32 size_t documentindex, index; 33 bool highlighted, ignoreflags; 34 std::list<RendererFormat> formats; 35 std::string text; 36 formatTextRendererLine37 std::string formatText(const RendererFormat& rf) const { return text.substr(rf.start, rf.length()); } lengthRendererLine38 size_t length() const { return text.length(); } 39 unformatRendererLine40 std::list<RendererFormat>::iterator unformat(size_t start, size_t end) { 41 auto begit = std::find_if(formats.begin(), formats.end(), [=](const RendererFormat& rf) -> bool { return rf.contains(start); }); 42 auto endit = std::find_if(formats.begin(), formats.end(), [=](const RendererFormat& rf) -> bool { return rf.contains(end); }); 43 44 RendererFormat begrf = *begit, endrf = *endit; 45 auto it = formats.erase(begit, ++endit); 46 47 begrf.end = start - 1; // Shrink first part 48 endrf.start = end + 1; // Shrink last part 49 50 if(!begrf.empty()) 51 { 52 it = formats.insert(it, begrf); 53 it++; 54 } 55 56 if(!endrf.empty()) 57 it = formats.insert(it, endrf); 58 59 return it; 60 } 61 62 RendererLine& format(size_t start, size_t end, const std::string& fgstyle = std::string(), const std::string& bgstyle = std::string()) { 63 if(text.empty() || (start >= text.size())) 64 return *this; 65 66 end = std::min(end, text.size() - 1); 67 68 auto it = this->unformat(start, end); 69 formats.insert(it, { start, end, fgstyle, bgstyle }); 70 return *this; 71 } 72 73 RendererLine& push(const std::string& text, const std::string& fgstyle = std::string(), const std::string& bgstyle = std::string()) { 74 size_t start = this->text.size(); 75 formats.push_back({ start, start + text.length() - 1, fgstyle, bgstyle}); 76 this->text += text; 77 return *this; 78 } 79 }; 80 81 class ListingRenderer 82 { 83 public: 84 typedef std::pair<size_t, size_t> Range; 85 enum: u32 { Normal = 0, HideSegmentName = 1, HideAddress = 2, 86 HideSegmentAndAddress = HideSegmentName | HideAddress }; 87 88 public: 89 ListingRenderer(DisassemblerAPI* disassembler); 90 virtual ~ListingRenderer() = default; 91 virtual void render(size_t start, size_t count, void* userdata = nullptr); 92 DisassemblerAPI* disassembler() const; 93 const ListingDocument& document() const; 94 const REDasm::Symbol* symbolUnderCursor(); 95 ListingDocument& document(); 96 void setFlags(u32 flags); 97 std::string wordFromPosition(const ListingCursor::Position& pos, ListingRenderer::Range *wordpos = nullptr); 98 std::string getCurrentWord(); 99 size_t getLastColumn(size_t line); 100 std::string getLine(size_t line); 101 std::string getSelectedText(); 102 103 protected: 104 virtual void renderLine(const RendererLine& rl) = 0; 105 bool hasFlag(u32 flag) const; 106 bool getRendererLine(size_t line, RendererLine& rl); 107 void renderSegment(const document_s_lock& lock, const ListingItem *item, RendererLine& rl); 108 void renderFunction(const document_s_lock &lock, const ListingItem *item, RendererLine &rl); 109 void renderInstruction(const document_s_lock &lock, const ListingItem *item, RendererLine &rl); 110 void renderSymbol(const document_s_lock &lock, const ListingItem *item, RendererLine &rl); 111 void renderMeta(const document_s_lock &lock, const ListingItem *item, RendererLine &rl); 112 void renderType(const document_s_lock &lock, const ListingItem *item, RendererLine &rl); 113 void renderAddress(const document_s_lock &lock, const ListingItem *item, RendererLine &rl); 114 void renderMnemonic(const InstructionPtr& instruction, RendererLine &rl); 115 void renderOperands(const InstructionPtr& instruction, RendererLine &rl); 116 void renderComments(const document_s_lock &lock, const ListingItem *item, RendererLine &rl); 117 void renderAddressIndent(const document_s_lock &lock, const ListingItem *item, RendererLine& rl); 118 void renderIndent(RendererLine &rl, int n = 1); 119 120 private: 121 bool renderSymbolPointer(const document_s_lock &lock, const Symbol *symbol, RendererLine& rl) const; 122 bool getRendererLine(const document_s_lock& lock, size_t line, RendererLine& rl); 123 void highlightSelection(RendererLine& rl); 124 void blinkCursor(RendererLine& rl); 125 void highlightWord(RendererLine& rl, const std::string word); 126 static std::string escapeString(const std::string& s); 127 128 protected: 129 ListingDocument& m_document; 130 DisassemblerAPI* m_disassembler; 131 ListingCursor* m_cursor; 132 133 private: 134 u32 m_flags; 135 PrinterPtr m_printer; 136 }; 137 138 } // namespace REDasm 139