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