mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-28 07:47:03 -05:00
feat: semantic syntax highlights for pattern editor. (#2214)
allows the ability to assign colors to global placed and non-placed variables, pattern, local and calculated pointer variables, template arguments, function variables and arguments, etc etc etc. It accomplishes this using the parser and the token sequence generated by the lexer. It still uses the original colorizing code but the underlying data holding the pattern has been updated to be easier to use and to debug. The changes are too numerous to cite here.It is a big but necessary step to bring the pattern editor to a somewhat useful state. There may be one commit in the pattern language repo needed to be able to run this code
This commit is contained in:
@@ -9,71 +9,89 @@
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
#include <regex>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include "imgui.h"
|
||||
#include "imgui_internal.h"
|
||||
|
||||
using strConstIter = std::string::const_iterator;
|
||||
// https://en.wikipedia.org/wiki/UTF-8
|
||||
// We assume that the char is a standalone character (<128) or a leading byte of an UTF-8 code sequence (non-10xxxxxx code)
|
||||
static int UTF8CharLength(uint8_t c) {
|
||||
if ((c & 0xFE) == 0xFC)
|
||||
return 6;
|
||||
if ((c & 0xFC) == 0xF8)
|
||||
return 5;
|
||||
if ((c & 0xF8) == 0xF0)
|
||||
return 4;
|
||||
if ((c & 0xF0) == 0xE0)
|
||||
return 3;
|
||||
if ((c & 0xE0) == 0xC0)
|
||||
return 2;
|
||||
return 1;
|
||||
}
|
||||
class TextEditor
|
||||
{
|
||||
public:
|
||||
enum class PaletteIndex
|
||||
{
|
||||
Default,
|
||||
Keyword,
|
||||
Number,
|
||||
String,
|
||||
CharLiteral,
|
||||
Punctuation,
|
||||
Preprocessor,
|
||||
Identifier,
|
||||
KnownIdentifier,
|
||||
PreprocIdentifier,
|
||||
GlobalDocComment,
|
||||
DocComment,
|
||||
Comment,
|
||||
MultiLineComment,
|
||||
PreprocessorDeactivated,
|
||||
Background,
|
||||
Directive,
|
||||
Operator,
|
||||
Separator,
|
||||
BuiltInType,
|
||||
Keyword,
|
||||
NumericLiteral,
|
||||
StringLiteral,
|
||||
CharLiteral,
|
||||
Cursor,
|
||||
Selection,
|
||||
ErrorMarker,
|
||||
Breakpoint,
|
||||
Background,
|
||||
LineNumber,
|
||||
Selection,
|
||||
Breakpoint,
|
||||
ErrorMarker,
|
||||
PreprocessorDeactivated,
|
||||
CurrentLineFill,
|
||||
CurrentLineFillInactive,
|
||||
CurrentLineEdge,
|
||||
ErrorText,
|
||||
WarningText,
|
||||
DebugText,
|
||||
DefaultText,
|
||||
Attribute,
|
||||
PatternVariable,
|
||||
LocalVariable,
|
||||
CalculatedPointer,
|
||||
TemplateArgument,
|
||||
Function,
|
||||
View,
|
||||
FunctionVariable,
|
||||
FunctionParameter,
|
||||
UserDefinedType,
|
||||
PlacedVariable,
|
||||
GlobalVariable,
|
||||
NameSpace,
|
||||
TypeDef,
|
||||
UnkIdentifier,
|
||||
DocComment,
|
||||
DocBlockComment,
|
||||
BlockComment,
|
||||
GlobalDocComment,
|
||||
Comment,
|
||||
PreprocIdentifier,
|
||||
Max
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
struct Breakpoint
|
||||
{
|
||||
int mLine;
|
||||
bool mEnabled;
|
||||
std::string mCondition;
|
||||
|
||||
Breakpoint()
|
||||
: mLine(-1)
|
||||
, mEnabled(false)
|
||||
{}
|
||||
};
|
||||
|
||||
// Represents a character coordinate from the user's point of view,
|
||||
// i. e. consider an uniform grid (assuming fixed-width font) on the
|
||||
// screen as it is rendered, and each cell has its own coordinate, starting from 0.
|
||||
// Tabs are counted as [1..mTabSize] count empty spaces, depending on
|
||||
// how many space is necessary to reach the next tab stop.
|
||||
// For example, coordinate (1, 5) represents the character 'B' in a line "\tABC", when mTabSize = 4,
|
||||
// because it is rendered as " ABC" on the screen.
|
||||
// indices of the arrays that contain the lines (vector) and the columns (a string) of the
|
||||
// text editor. Negative values indicate the distance to the last element of the array.
|
||||
// When comparing coordinates ensure they have the same sign because coordinates don't have
|
||||
// information about the size of the array. Currently positive coordinates are always bigger
|
||||
// than negatives even if that gives a wrong result.
|
||||
struct Coordinates
|
||||
{
|
||||
int mLine, mColumn;
|
||||
Coordinates() : mLine(0), mColumn(0) {}
|
||||
Coordinates(int aLine, int aColumn) : mLine(aLine), mColumn(aColumn)
|
||||
{
|
||||
IM_ASSERT(aLine >= 0);
|
||||
IM_ASSERT(aColumn >= 0);
|
||||
}
|
||||
static Coordinates Invalid() { static Coordinates invalid(-1, -1); return invalid; }
|
||||
Coordinates(int aLine, int aColumn) : mLine(aLine), mColumn(aColumn) {}
|
||||
|
||||
bool operator ==(const Coordinates& o) const
|
||||
{
|
||||
@@ -129,8 +147,8 @@ public:
|
||||
using Keywords = std::unordered_set<std::string> ;
|
||||
using ErrorMarkers = std::map<Coordinates, std::pair<uint32_t ,std::string>>;
|
||||
using Breakpoints = std::unordered_set<uint32_t>;
|
||||
using Palette = std::array<ImU32, (uint32_t)PaletteIndex::Max>;
|
||||
using Char = uint8_t ;
|
||||
using Palette = std::array<ImU32, (uint64_t )PaletteIndex::Max>;
|
||||
using Glyph = uint8_t ;
|
||||
|
||||
class ActionableBox {
|
||||
|
||||
@@ -203,35 +221,381 @@ public:
|
||||
};
|
||||
using ErrorHoverBoxes = std::map<Coordinates, ErrorHoverBox>;
|
||||
|
||||
struct Glyph
|
||||
{
|
||||
Char mChar;
|
||||
PaletteIndex mColorIndex = PaletteIndex::Default;
|
||||
bool mComment : 1;
|
||||
bool mMultiLineComment : 1;
|
||||
bool mPreprocessor : 1;
|
||||
bool mDocComment : 1;
|
||||
bool mGlobalDocComment : 1;
|
||||
bool mDeactivated : 1;
|
||||
// A line of text in the pattern editor consists of three strings; the character encoding, the color encoding and the flags.
|
||||
// The char encoding is utf-8, the color encoding are indices to the color palette and the flags are used to override the colors
|
||||
// depending on priorities; e.g. comments, strings, etc.
|
||||
|
||||
class Line {
|
||||
public:
|
||||
struct FlagBits {
|
||||
bool mComment : 1;
|
||||
bool mBlockComment : 1;
|
||||
bool mDocComment : 1;
|
||||
bool mBlockDocComment : 1;
|
||||
bool mGlobalDocComment : 1;
|
||||
bool mDeactivated : 1;
|
||||
bool mPreprocessor : 1;
|
||||
};
|
||||
union Flags {
|
||||
Flags(char value) : mValue(value) {}
|
||||
Flags(FlagBits bits) : mBits(bits) {}
|
||||
FlagBits mBits;
|
||||
char mValue;
|
||||
};
|
||||
constexpr static char InComment = 31;
|
||||
|
||||
Glyph(Char aChar, PaletteIndex aColorIndex) : mChar(aChar), mColorIndex(aColorIndex), mComment(false),
|
||||
mMultiLineComment(false), mPreprocessor(false), mDocComment(false), mGlobalDocComment(false), mDeactivated(false) {}
|
||||
};
|
||||
class LineIterator {
|
||||
public:
|
||||
strConstIter mCharsIter;
|
||||
strConstIter mColorsIter;
|
||||
strConstIter mFlagsIter;
|
||||
|
||||
typedef std::vector<Glyph> Line;
|
||||
typedef std::vector<Line> Lines;
|
||||
LineIterator(const LineIterator &other) : mCharsIter(other.mCharsIter), mColorsIter(other.mColorsIter), mFlagsIter(other.mFlagsIter) {}
|
||||
|
||||
LineIterator() = default;
|
||||
|
||||
char operator*() {
|
||||
return *mCharsIter;
|
||||
}
|
||||
|
||||
LineIterator operator++() {
|
||||
LineIterator iter = *this;
|
||||
++iter.mCharsIter;
|
||||
++iter.mColorsIter;
|
||||
++iter.mFlagsIter;
|
||||
return iter;
|
||||
}
|
||||
|
||||
LineIterator operator=(const LineIterator &other) {
|
||||
mCharsIter = other.mCharsIter;
|
||||
mColorsIter = other.mColorsIter;
|
||||
mFlagsIter = other.mFlagsIter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator!=(const LineIterator &other) const {
|
||||
return mCharsIter != other.mCharsIter || mColorsIter != other.mColorsIter || mFlagsIter != other.mFlagsIter;
|
||||
}
|
||||
|
||||
bool operator==(const LineIterator &other) const {
|
||||
return mCharsIter == other.mCharsIter && mColorsIter == other.mColorsIter && mFlagsIter == other.mFlagsIter;
|
||||
}
|
||||
|
||||
LineIterator operator+(int n) {
|
||||
LineIterator iter = *this;
|
||||
iter.mCharsIter += n;
|
||||
iter.mColorsIter += n;
|
||||
iter.mFlagsIter += n;
|
||||
return iter;
|
||||
}
|
||||
|
||||
int operator-(LineIterator l) {
|
||||
return mCharsIter - l.mCharsIter;
|
||||
}
|
||||
};
|
||||
|
||||
LineIterator begin() const {
|
||||
LineIterator iter;
|
||||
iter.mCharsIter = mChars.begin();
|
||||
iter.mColorsIter = mColors.begin();
|
||||
iter.mFlagsIter = mFlags.begin();
|
||||
return iter;
|
||||
}
|
||||
|
||||
LineIterator end() const {
|
||||
LineIterator iter;
|
||||
iter.mCharsIter = mChars.end();
|
||||
iter.mColorsIter = mColors.end();
|
||||
iter.mFlagsIter = mFlags.end();
|
||||
return iter;
|
||||
}
|
||||
|
||||
std::string mChars;
|
||||
std::string mColors;
|
||||
std::string mFlags;
|
||||
bool mColorized = false;
|
||||
Line() : mChars(), mColors(), mFlags(), mColorized(false) {}
|
||||
|
||||
explicit Line(const char *line) {
|
||||
Line(std::string(line));
|
||||
}
|
||||
|
||||
explicit Line(const std::string &line) : mChars(line), mColors(std::string(line.size(), 0x00)), mFlags(std::string(line.size(), 0x00)), mColorized(false) {}
|
||||
Line(const Line &line) : mChars(line.mChars), mColors(line.mColors), mFlags(line.mFlags), mColorized(line.mColorized) {}
|
||||
|
||||
LineIterator begin() {
|
||||
LineIterator iter;
|
||||
iter.mCharsIter = mChars.begin();
|
||||
iter.mColorsIter = mColors.begin();
|
||||
iter.mFlagsIter = mFlags.begin();
|
||||
return iter;
|
||||
}
|
||||
|
||||
LineIterator end() {
|
||||
LineIterator iter;
|
||||
iter.mCharsIter = mChars.end();
|
||||
iter.mColorsIter = mColors.end();
|
||||
iter.mFlagsIter = mFlags.end();
|
||||
return iter;
|
||||
}
|
||||
|
||||
Line &operator=(const Line &line) {
|
||||
mChars = line.mChars;
|
||||
mColors = line.mColors;
|
||||
mFlags = line.mFlags;
|
||||
mColorized = line.mColorized;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Line &operator=(Line &&line) noexcept {
|
||||
mChars = std::move(line.mChars);
|
||||
mColors = std::move(line.mColors);
|
||||
mFlags = std::move(line.mFlags);
|
||||
mColorized = line.mColorized;
|
||||
return *this;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return mChars.size();
|
||||
}
|
||||
enum class LinePart {
|
||||
Chars,
|
||||
Colors,
|
||||
Flags
|
||||
};
|
||||
|
||||
char front(LinePart part = LinePart::Chars) const {
|
||||
if (part == LinePart::Chars && !mChars.empty())
|
||||
return mChars.front();
|
||||
if (part == LinePart::Colors && !mColors.empty())
|
||||
return mColors.front();
|
||||
if (part == LinePart::Flags && !mFlags.empty())
|
||||
return mFlags.front();
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void push_back(char c) {
|
||||
mChars.push_back(c);
|
||||
mColors.push_back(0x00);
|
||||
mFlags.push_back(0x00);
|
||||
mColorized = false;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return mChars.empty();
|
||||
}
|
||||
|
||||
std::string substrUtf8(size_t start, size_t length = (size_t)-1, LinePart part = LinePart::Chars ) const {
|
||||
if (start >= mChars.size())
|
||||
return "";
|
||||
if (length == (size_t)-1 || length >= mChars.size() - start)
|
||||
length = mChars.size() - start;
|
||||
size_t utf8Start= 0;
|
||||
while (utf8Start<start) {
|
||||
auto d = UTF8CharLength(mChars[utf8Start]);
|
||||
utf8Start+= d;
|
||||
}
|
||||
size_t utf8Length = 0;
|
||||
while (utf8Length < length && utf8Start + utf8Length < mChars.size()) {
|
||||
auto d = UTF8CharLength(mChars[utf8Start + utf8Length]);
|
||||
utf8Length += d;
|
||||
}
|
||||
|
||||
if (part == LinePart::Chars)
|
||||
return mChars.substr(utf8Start, utf8Length);
|
||||
if (part == LinePart::Colors)
|
||||
return mColors.substr(utf8Start, utf8Length);
|
||||
if (part == LinePart::Flags)
|
||||
return mFlags.substr(utf8Start, utf8Length);
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string substr(size_t start, size_t length = (size_t)-1, LinePart part = LinePart::Chars ) const {
|
||||
if (length == (size_t)-1)
|
||||
length = mChars.size() - start;
|
||||
if (start >= mChars.size())
|
||||
return "";
|
||||
if (start + length >= mChars.size())
|
||||
length = mChars.size() - start;
|
||||
if (part == LinePart::Chars && length > 0)
|
||||
return mChars.substr(start, length);
|
||||
if (part == LinePart::Colors && length > 0)
|
||||
return mColors.substr(start, length);
|
||||
if (part == LinePart::Flags && length > 0)
|
||||
return mFlags.substr(start, length);
|
||||
return "";
|
||||
}
|
||||
|
||||
template<LinePart part=LinePart::Chars>
|
||||
char operator[](size_t index) const {
|
||||
if (part == LinePart::Chars)
|
||||
return mChars[index];
|
||||
if (part == LinePart::Colors)
|
||||
return mColors[index];
|
||||
if (part == LinePart::Flags)
|
||||
return mFlags[index];
|
||||
return mChars[index];
|
||||
}
|
||||
|
||||
template<LinePart part=LinePart::Chars>
|
||||
const char &operator[](size_t index) {
|
||||
if (part == LinePart::Chars)
|
||||
return mChars[index];
|
||||
if (part == LinePart::Colors)
|
||||
return mColors[index];
|
||||
if (part == LinePart::Flags)
|
||||
return mFlags[index];
|
||||
return mChars[index];
|
||||
}
|
||||
|
||||
void SetNeedsUpdate(bool needsUpdate) {
|
||||
mColorized = mColorized && !needsUpdate;
|
||||
}
|
||||
|
||||
void append(const char *text) {
|
||||
append(std::string(text));
|
||||
}
|
||||
|
||||
void append(const char text) {
|
||||
append(std::string(1, text));
|
||||
}
|
||||
|
||||
void append(const std::string &text) {
|
||||
mChars.append(text);
|
||||
mColors.append(text.size(), 0x00);
|
||||
mFlags.append(text.size(), 0x00);
|
||||
mColorized = false;
|
||||
}
|
||||
|
||||
void append(const Line &line) {
|
||||
append(line.begin(), line.end());
|
||||
}
|
||||
|
||||
void append(LineIterator begin, LineIterator end) {
|
||||
if (begin.mCharsIter < end.mCharsIter)
|
||||
mChars.append(begin.mCharsIter, end.mCharsIter);
|
||||
if (begin.mColorsIter < end.mColorsIter)
|
||||
mColors.append(begin.mColorsIter, end.mColorsIter);
|
||||
if (begin.mFlagsIter < end.mFlagsIter)
|
||||
mFlags.append(begin.mFlagsIter, end.mFlagsIter);
|
||||
mColorized = false;
|
||||
}
|
||||
|
||||
void insert(LineIterator iter, const std::string &text) {
|
||||
if (iter == end())
|
||||
append(text);
|
||||
else
|
||||
insert(iter, text.begin(), text.end());
|
||||
}
|
||||
|
||||
void insert(LineIterator iter, const char text) {
|
||||
if (iter == end())
|
||||
append(text);
|
||||
else
|
||||
insert(iter,std::string(1, text));
|
||||
}
|
||||
|
||||
void insert(LineIterator iter, strConstIter beginString, strConstIter endString) {
|
||||
if (iter == end())
|
||||
append(std::string(beginString, endString));
|
||||
else {
|
||||
std::string charsString(beginString, endString);
|
||||
mChars.insert(iter.mCharsIter, beginString, endString);
|
||||
std::string colorString(charsString.size(), 0x00);
|
||||
try {
|
||||
mColors.insert(iter.mColorsIter, colorString.begin(), colorString.end());
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "Exception: " << e.what() << std::endl;
|
||||
mColorized = false;
|
||||
return;
|
||||
}
|
||||
std::string flagsString(charsString.size(), 0x00);
|
||||
try {
|
||||
mFlags.insert(iter.mFlagsIter, flagsString.begin(), flagsString.end());
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "Exception: " << e.what() << std::endl;
|
||||
mColorized = false;
|
||||
return;
|
||||
}
|
||||
mColorized = false;
|
||||
}
|
||||
}
|
||||
|
||||
void insert(LineIterator iter,const Line &line) {
|
||||
if (iter == end())
|
||||
append(line.begin(), line.end());
|
||||
else
|
||||
insert(iter, line.begin(), line.end());
|
||||
}
|
||||
|
||||
void insert(LineIterator iter,LineIterator beginLine, LineIterator endLine) {
|
||||
if (iter == end())
|
||||
append(beginLine, endLine);
|
||||
else {
|
||||
mChars.insert(iter.mCharsIter, beginLine.mCharsIter, endLine.mCharsIter);
|
||||
mColors.insert(iter.mColorsIter, beginLine.mColorsIter, endLine.mColorsIter);
|
||||
mFlags.insert(iter.mFlagsIter, beginLine.mFlagsIter, endLine.mFlagsIter);
|
||||
mColorized = false;
|
||||
}
|
||||
}
|
||||
|
||||
void erase(LineIterator begin) {
|
||||
mChars.erase(begin.mCharsIter);
|
||||
mColors.erase(begin.mColorsIter);
|
||||
mFlags.erase(begin.mFlagsIter);
|
||||
mColorized = false;
|
||||
}
|
||||
|
||||
void erase(LineIterator begin, size_t count) {
|
||||
if (count == (size_t) -1)
|
||||
count = mChars.size() - (begin.mCharsIter - mChars.begin());
|
||||
mChars.erase(begin.mCharsIter, begin.mCharsIter + count);
|
||||
mColors.erase(begin.mColorsIter, begin.mColorsIter + count);
|
||||
mFlags.erase(begin.mFlagsIter, begin.mFlagsIter + count);
|
||||
mColorized = false;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
mChars.clear();
|
||||
mColors.clear();
|
||||
mFlags.clear();
|
||||
mColorized = false;
|
||||
}
|
||||
|
||||
void SetLine(const std::string &text) {
|
||||
mChars = text;
|
||||
mColors = std::string(text.size(), 0x00);
|
||||
mFlags = std::string(text.size(), 0x00);
|
||||
mColorized = false;
|
||||
}
|
||||
|
||||
void SetLine(const Line &text) {
|
||||
mChars = text.mChars;
|
||||
mColors = text.mColors;
|
||||
mFlags = text.mFlags;
|
||||
mColorized = text.mColorized;
|
||||
}
|
||||
|
||||
|
||||
bool NeedsUpdate() const {
|
||||
return !mColorized;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
using Lines = std::vector<Line>;
|
||||
|
||||
struct LanguageDefinition
|
||||
{
|
||||
typedef std::pair<std::string, PaletteIndex> TokenRegexString;
|
||||
typedef std::vector<TokenRegexString> TokenRegexStrings;
|
||||
typedef bool(*TokenizeCallback)(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end, PaletteIndex & paletteIndex);
|
||||
typedef bool(*TokenizeCallback)(strConstIter in_begin, strConstIter in_end, strConstIter &out_begin, strConstIter &out_end, PaletteIndex &paletteIndex);
|
||||
|
||||
std::string mName;
|
||||
Keywords mKeywords;
|
||||
Identifiers mIdentifiers;
|
||||
Identifiers mPreprocIdentifiers;
|
||||
std::string mCommentStart, mCommentEnd, mSingleLineComment, mGlobalDocComment, mDocComment;
|
||||
std::string mSingleLineComment, mCommentEnd, mCommentStart, mGlobalDocComment, mDocComment, mBlockDocComment;
|
||||
char mPreprocChar;
|
||||
bool mAutoIndentation;
|
||||
|
||||
@@ -241,10 +605,8 @@ public:
|
||||
|
||||
bool mCaseSensitive;
|
||||
|
||||
LanguageDefinition()
|
||||
: mPreprocChar('#'), mAutoIndentation(true), mTokenize(nullptr), mCaseSensitive(true)
|
||||
{
|
||||
}
|
||||
LanguageDefinition() : mName(""), mKeywords({}), mIdentifiers({}), mPreprocIdentifiers({}), mSingleLineComment(""), mCommentEnd(""),
|
||||
mCommentStart(""), mGlobalDocComment(""), mDocComment(""), mBlockDocComment(""), mPreprocChar('#'), mAutoIndentation(true), mTokenize(nullptr), mTokenRegexStrings({}), mCaseSensitive(true) {}
|
||||
|
||||
static const LanguageDefinition& CPlusPlus();
|
||||
static const LanguageDefinition& HLSL();
|
||||
@@ -303,10 +665,59 @@ public:
|
||||
}
|
||||
std::string GetText() const;
|
||||
bool isEmpty() const {
|
||||
auto text = GetText();
|
||||
return text.empty() || text == "\n";
|
||||
if (mLines.empty())
|
||||
return true;
|
||||
if (mLines.size() == 1) {
|
||||
if (mLines[0].empty())
|
||||
return true;
|
||||
if (mLines[0].size() == 1 && mLines[0].front() == '\n')
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SetTopLine();
|
||||
uint32_t GetTopLine() const {
|
||||
return static_cast<uint32_t>(std::floor(mTopLine));
|
||||
}
|
||||
uint32_t GetBottomLine() const {
|
||||
return static_cast<uint32_t>(std::ceil(mTopLine+mNumberOfLinesDisplayed));
|
||||
}
|
||||
void SetNeedsUpdate (uint32_t line, bool needsUpdate) {
|
||||
if (line < mLines.size())
|
||||
mLines[line].SetNeedsUpdate(needsUpdate);
|
||||
}
|
||||
|
||||
void SetColorizedLineSize(size_t line) {
|
||||
if (line < mLines.size()) {
|
||||
const auto &size = mLines[line].mChars.size();
|
||||
if (mLines[line].mColors.size() != size) {
|
||||
mLines[line].mColors.resize(size);
|
||||
std::fill(mLines[line].mColors.begin(), mLines[line].mColors.end(), 0x00);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetColorizedLine(size_t line, const std::string &tokens) {
|
||||
if (line < mLines.size()) {
|
||||
auto &lineTokens = mLines[line].mColors;
|
||||
if (lineTokens.size() != tokens.size()) {
|
||||
lineTokens.resize(tokens.size());
|
||||
std::fill(lineTokens.begin(), lineTokens.end(), 0x00);
|
||||
}
|
||||
bool needsUpdate = false;
|
||||
for (size_t i = 0; i < tokens.size(); ++i) {
|
||||
if (tokens[i] != 0x00) {
|
||||
if (tokens[i] != lineTokens[i]) {
|
||||
lineTokens[i] = tokens[i];
|
||||
needsUpdate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
SetNeedsUpdate(line, needsUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
void SetScrollY();
|
||||
void SetTextLines(const std::vector<std::string>& aLines);
|
||||
std::vector<std::string> GetTextLines() const;
|
||||
@@ -345,14 +756,23 @@ public:
|
||||
void SetOverwrite(bool aValue) { mOverwrite = aValue; }
|
||||
|
||||
std::string ReplaceStrings(std::string string, const std::string &search, const std::string &replace);
|
||||
std::vector<std::string> SplitString(const std::string &string, const std::string &delimiter, bool removeEmpty);
|
||||
static std::vector<std::string> SplitString(const std::string &string, const std::string &delimiter, bool removeEmpty);
|
||||
std::string ReplaceTabsWithSpaces(const std::string& string, uint32_t tabSize);
|
||||
std::string PreprocessText(const std::string &code);
|
||||
|
||||
void SetReadOnly(bool aValue);
|
||||
bool IsEndOfLine(const Coordinates &aCoordinates) const;
|
||||
bool IsEndOfFile(const Coordinates &aCoordinates) const;
|
||||
bool IsReadOnly() const { return mReadOnly; }
|
||||
bool IsTextChanged() const { return mTextChanged; }
|
||||
void SetTextChanged(bool aValue=false) { mTextChanged = aValue; }
|
||||
void SetTextChanged(bool aValue) { mTextChanged = aValue; }
|
||||
void SetTimeStamp(int code) {
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
if (code == 0)
|
||||
mLinesTimestamp = std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count();
|
||||
else
|
||||
mColorizedLinesTimestamp = std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count();
|
||||
}
|
||||
bool IsCursorPositionChanged() const { return mCursorPositionChanged; }
|
||||
bool IsBreakpointsChanged() const { return mBreakPointsChanged; }
|
||||
void ClearBreakpointsChanged() { mBreakPointsChanged = false; }
|
||||
@@ -362,6 +782,7 @@ public:
|
||||
|
||||
bool IsColorizerEnabled() const { return mColorizerEnabled; }
|
||||
void SetColorizerEnable(bool aValue);
|
||||
void Colorize();
|
||||
|
||||
Coordinates GetCursorPosition() const { return GetActualCursorCoordinates(); }
|
||||
void SetCursorPosition(const Coordinates& aPosition);
|
||||
@@ -541,8 +962,7 @@ private:
|
||||
typedef std::vector<UndoRecord> UndoBuffer;
|
||||
|
||||
void ProcessInputs();
|
||||
void Colorize(int aFromLine = 0, int aCount = -1);
|
||||
void ColorizeRange(int aFromLine = 0, int aToLine = 0);
|
||||
void ColorizeRange();
|
||||
void ColorizeInternal();
|
||||
float TextDistanceToLineStart(const Coordinates& aFrom) const;
|
||||
void EnsureCursorVisible();
|
||||
@@ -553,35 +973,40 @@ private:
|
||||
void DeleteRange(const Coordinates& aStart, const Coordinates& aEnd);
|
||||
int InsertTextAt(Coordinates& aWhere, const std::string &aValue);
|
||||
void AddUndo(UndoRecord& aValue);
|
||||
Coordinates ScreenPosToCoordinates(const ImVec2& aPosition) const;
|
||||
Coordinates ScreenPosToCoordinates(const ImVec2& aPosition) const;
|
||||
Coordinates FindWordStart(const Coordinates& aFrom) const;
|
||||
Coordinates FindWordEnd(const Coordinates& aFrom) const;
|
||||
Coordinates FindPreviousWord(const Coordinates& aFrom) const;
|
||||
Coordinates FindNextWord(const Coordinates& aFrom) const;
|
||||
Coordinates StringIndexToCoordinates(int aIndex, const std::string &str) const;
|
||||
int GetCharacterIndex(const Coordinates& aCoordinates) const;
|
||||
int GetCharacterColumn(int aLine, int aIndex) const;
|
||||
int GetLineCharacterCount(int aLine) const;
|
||||
int Utf8CharsToBytes(const Coordinates &aCoordinates) const;
|
||||
unsigned long long GetLineByteCount(int aLine) const;
|
||||
int Utf8CharsToBytes(const Coordinates &aCoordinates) const;
|
||||
static int Utf8CharsToBytes(std::string line, uint32_t start, uint32_t numChars);
|
||||
unsigned long long GetLineByteCount(int aLine) const;
|
||||
int GetStringCharacterCount(std::string str) const;
|
||||
int GetLineMaxColumn(int aLine) const;
|
||||
bool IsOnWordBoundary(const Coordinates& aAt) const;
|
||||
void RemoveLine(int aStart, int aEnd);
|
||||
void RemoveLine(int aIndex);
|
||||
Line& InsertLine(int aIndex);
|
||||
void EnterCharacter(ImWchar aChar, bool aShift);
|
||||
void InsertLine(int aIndex, const std::string &aText);
|
||||
void EnterCharacter(ImWchar aChar, bool aShift);
|
||||
void DeleteSelection();
|
||||
std::string GetWordUnderCursor() const;
|
||||
std::string GetWordAt(const Coordinates& aCoords) const;
|
||||
ImU32 GetGlyphColor(const Glyph& aGlyph) const;
|
||||
TextEditor::PaletteIndex GetColorIndexFromFlags(Line::Flags flags);
|
||||
void ResetCursorBlinkTime();
|
||||
|
||||
uint32_t SkipSpaces(const Coordinates &aFrom);
|
||||
void HandleKeyboardInputs();
|
||||
void HandleMouseInputs();
|
||||
void RenderText(const char *aTitle, const ImVec2 &lineNumbersStartPos, const ImVec2 &textEditorSize);
|
||||
void SetFocus();
|
||||
float mLineSpacing = 1.0F;
|
||||
Lines mLines;
|
||||
uint64_t mLinesTimestamp = 0;
|
||||
uint64_t mColorizedLinesTimestamp = 0;
|
||||
EditorState mState = {};
|
||||
UndoBuffer mUndoBuffer;
|
||||
int mUndoIndex = 0;
|
||||
@@ -616,7 +1041,7 @@ private:
|
||||
Palette mPalette = {};
|
||||
LanguageDefinition mLanguageDefinition = {};
|
||||
RegexList mRegexList;
|
||||
bool mCheckComments = true;
|
||||
bool mUpdateFlags = true;
|
||||
Breakpoints mBreakpoints = {};
|
||||
ErrorMarkers mErrorMarkers = {};
|
||||
ErrorHoverBoxes mErrorHoverBoxes = {};
|
||||
@@ -646,8 +1071,9 @@ private:
|
||||
static const int sCursorBlinkOnTime;
|
||||
};
|
||||
|
||||
bool TokenizeCStyleString(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end);
|
||||
bool TokenizeCStyleCharacterLiteral(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end);
|
||||
bool TokenizeCStyleIdentifier(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end);
|
||||
bool TokenizeCStyleNumber(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end);
|
||||
bool TokenizeCStylePunctuation(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end);
|
||||
bool TokenizeCStyleString(strConstIter in_begin, strConstIter in_end, strConstIter &out_begin, strConstIter &out_end);
|
||||
bool TokenizeCStyleCharacterLiteral(strConstIter in_begin, strConstIter in_end, strConstIter &out_begin, strConstIter &out_end);
|
||||
bool TokenizeCStyleIdentifier(strConstIter in_begin, strConstIter in_end, strConstIter &out_begin, strConstIter &out_end);
|
||||
bool TokenizeCStyleNumber(strConstIter in_begin, strConstIter in_end, strConstIter &out_begin, strConstIter &out_end);
|
||||
bool TokenizeCStyleOperator(strConstIter in_begin, strConstIter in_end, strConstIter &out_begin, strConstIter &out_end);
|
||||
bool TokenizeCStyleSeparator(strConstIter in_begin, strConstIter in_end, strConstIter &out_begin, strConstIter &out_end);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,8 +2,6 @@
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <hex/api/plugin_manager.hpp>
|
||||
#include <hex/api/content_registry.hpp>
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
|
||||
@@ -119,6 +119,8 @@ add_imhex_plugin(
|
||||
source/content/views/view_achievements.cpp
|
||||
source/content/views/view_highlight_rules.cpp
|
||||
source/content/views/view_tutorials.cpp
|
||||
|
||||
source/content/text_highlighting/pattern_language.cpp
|
||||
INCLUDES
|
||||
include
|
||||
|
||||
|
||||
@@ -0,0 +1,419 @@
|
||||
#pragma once
|
||||
#include <pl/core/token.hpp>
|
||||
#include <pl/core/preprocessor.hpp>
|
||||
#include <pl/helpers/safe_iterator.hpp>
|
||||
#include <TextEditor.h>
|
||||
#include <hex/helpers/types.hpp>
|
||||
|
||||
namespace pl {
|
||||
class PatternLanguage;
|
||||
}
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
class ViewPatternEditor;
|
||||
class TextHighlighter {
|
||||
public:
|
||||
class Interval;
|
||||
using Token = pl::core::Token;
|
||||
using ASTNode = pl::core::ast::ASTNode;
|
||||
using ExcludedLocation = pl::core::Preprocessor::ExcludedLocation;
|
||||
using CompileError = pl::core::err::CompileError;
|
||||
using Identifier = Token::Identifier;
|
||||
using IdentifierType = Identifier::IdentifierType;
|
||||
using UnorderedBlocks = std::map<std::string,Interval>;
|
||||
using OrderedBlocks = std::map<Interval,std::string>;
|
||||
using Scopes = std::set<Interval>;
|
||||
using Location = pl::core::Location;
|
||||
using TokenIter = pl::hlp::SafeIterator<std::vector<Token>::const_iterator>;
|
||||
using VariableScopes = std::map<std::string,Scopes>;
|
||||
using Inheritances = std::map<std::string,std::vector<std::string>>;
|
||||
using IdentifierTypeColor = std::map<Identifier::IdentifierType,TextEditor::PaletteIndex>;
|
||||
using TokenTypeColor = std::map<Token::Type,TextEditor::PaletteIndex>;
|
||||
using TokenColor = std::map<Token *,TextEditor::PaletteIndex>;
|
||||
|
||||
struct ParentDefinition;
|
||||
struct Definition {
|
||||
Definition()= default;
|
||||
Definition(IdentifierType identifierType, std::string typeStr,i32 tokenId, Location location) : idType(identifierType), typeStr(typeStr), tokenIndex(tokenId),location(location) {}
|
||||
IdentifierType idType;
|
||||
std::string typeStr;
|
||||
i32 tokenIndex;
|
||||
Location location;
|
||||
};
|
||||
|
||||
struct ParentDefinition {
|
||||
ParentDefinition() = default;
|
||||
ParentDefinition(IdentifierType identifierType, i32 tokenId, Location location) : idType(identifierType), tokenIndex(tokenId), location(location) {}
|
||||
IdentifierType idType;
|
||||
i32 tokenIndex;
|
||||
Location location;
|
||||
};
|
||||
/// to define functions and types
|
||||
using Definitions = std::map<std::string,ParentDefinition>;
|
||||
/// to define global variables
|
||||
using Variables = std::map<std::string,std::vector<Definition>>;
|
||||
/// to define UDT and function variables
|
||||
using VariableMap = std::map<std::string,Variables>;
|
||||
private:
|
||||
std::string m_text;
|
||||
std::vector<std::string> m_lines;
|
||||
std::vector<i32> m_firstTokenIdOfLine;
|
||||
ViewPatternEditor *m_viewPatternEditor;
|
||||
std::vector<ExcludedLocation> m_excludedLocations;
|
||||
std::vector<Token> m_tokens;
|
||||
TokenColor m_tokenColors;
|
||||
std::unique_ptr<pl::PatternLanguage> *patternLanguage;
|
||||
std::vector<CompileError> m_compileErrors;
|
||||
std::map<std::string,std::vector<i32>> m_instances;
|
||||
Definitions m_UDTDefinitions;
|
||||
Definitions m_functionDefinitions;
|
||||
|
||||
OrderedBlocks m_namespaceTokenRange;
|
||||
UnorderedBlocks m_UDTTokenRange;
|
||||
UnorderedBlocks m_functionTokenRange;
|
||||
Scopes m_globalTokenRange;
|
||||
|
||||
VariableMap m_UDTVariables;
|
||||
VariableMap m_functionVariables;
|
||||
Variables m_globalVariables;
|
||||
|
||||
std::map<std::string,std::string> m_attributeFunctionArgumentType;
|
||||
std::map<std::string,std::string> m_typeDefMap;
|
||||
std::map<std::string,std::string> m_typeDefInvMap;
|
||||
std::vector<std::string> m_nameSpaces;
|
||||
std::vector<std::string> m_UDTs;
|
||||
std::set<i32> m_taggedIdentifiers;
|
||||
std::set<i32> m_memberChains;
|
||||
std::set<i32> m_scopeChains;
|
||||
|
||||
TokenIter m_curr;
|
||||
TokenIter m_startToken, m_originalPosition, m_partOriginalPosition;
|
||||
|
||||
VariableScopes m_UDTBlocks;
|
||||
VariableScopes m_functionBlocks;
|
||||
Scopes m_globalBlocks;
|
||||
Inheritances m_inheritances;
|
||||
const static IdentifierTypeColor m_identifierTypeColor;
|
||||
const static TokenTypeColor m_tokenTypeColor;
|
||||
|
||||
i32 m_runningColorizers=0;
|
||||
public:
|
||||
|
||||
/// Intervals are the sets finite contiguous non-negative integer that
|
||||
/// are described by their endpoints. The sets must have the following
|
||||
/// properties:
|
||||
/// 1. Any two elements of the set can either have an empty intersection or
|
||||
/// 2. their intersection is equal to one of the two sets (i.e. one is
|
||||
/// a subset of the other).
|
||||
/// An interval is defined to be smaller than another if:
|
||||
/// 1. The interval lies entirely to the left of the other interval or
|
||||
/// 2. The interval is a proper subset of the other interval.
|
||||
/// Two intervals are equal if they have identical start and end values.
|
||||
/// This ordering is used for things like code blocks or the token
|
||||
/// ranges that are defined by the blocks.
|
||||
class Interval {
|
||||
public:
|
||||
i32 start;
|
||||
i32 end;
|
||||
Interval() : start(0), end(0) {}
|
||||
Interval(i32 start, i32 end) : start(start), end(end) {
|
||||
if (start > end)
|
||||
throw std::invalid_argument("Interval start must be less than or equal to end");
|
||||
}
|
||||
bool operator<(const Interval &other) const {
|
||||
return other.end > end;
|
||||
}
|
||||
bool operator>(const Interval &other) const {
|
||||
return end > other.end;
|
||||
}
|
||||
bool operator==(const Interval &other) const {
|
||||
return start == other.start && end == other.end;
|
||||
}
|
||||
bool operator!=(const Interval &other) const {
|
||||
return start != other.start || end != other.end;
|
||||
}
|
||||
bool operator<=(const Interval &other) const {
|
||||
return other.end >= end;
|
||||
}
|
||||
bool operator>=(const Interval &other) const {
|
||||
return end >= other.end;
|
||||
}
|
||||
bool contains(const Interval &other) const {
|
||||
return other.start >= start && other.end <= end;
|
||||
}
|
||||
bool contains(i32 value) const {
|
||||
return value >= start && value <= end;
|
||||
}
|
||||
bool contiguous(const Interval &other) const {
|
||||
return ((start - other.end) == 1 || (other.start - end) == 1);
|
||||
}
|
||||
};
|
||||
std::atomic<bool> m_needsToUpdateColors = true;
|
||||
std::atomic<bool> m_wasInterrupted = false;
|
||||
|
||||
TextHighlighter(ViewPatternEditor *viewPatternEditor, std::unique_ptr<pl::PatternLanguage> *patternLanguage ) :
|
||||
m_viewPatternEditor(viewPatternEditor), patternLanguage(patternLanguage), m_needsToUpdateColors(true) {}
|
||||
/**
|
||||
* @brief Entry point to syntax highlighting
|
||||
*/
|
||||
void highlightSourceCode();
|
||||
|
||||
/**
|
||||
* @brief Syntax highlighting from parser
|
||||
*/
|
||||
void setInitialColors();
|
||||
/**
|
||||
* @brief Create data to pass to text editor
|
||||
*/
|
||||
void setRequestedIdentifierColors();
|
||||
/**
|
||||
* @brief Set the color of a token
|
||||
*/
|
||||
void setColor(i32 tokenId=-1, const IdentifierType &type = IdentifierType::Unknown);
|
||||
void setIdentifierColor(i32 tokenId=-1, const IdentifierType &type = IdentifierType::Unknown);
|
||||
/**
|
||||
* @brief Only identifiers not in chains should remain
|
||||
*/
|
||||
void colorRemainingIdentifierTokens();
|
||||
/**
|
||||
* @brief Renders compile errors in real time
|
||||
*/
|
||||
void renderErrors();
|
||||
/// A token range is the set of token indices of a definition. The namespace token
|
||||
/// ranges are obtained first because they are needed to obtain unique identifiers.
|
||||
void getAllTokenRanges(IdentifierType idtype);
|
||||
/// The global scope is the complement of the union of all the function and UDT token ranges
|
||||
void getGlobalTokenRanges();
|
||||
/// If the current token is a function or UDT, creates a map entry from the name to the token range. These are ordered alphabetically by name.
|
||||
/// If the current token is a namespace, creates a map entry from the token range to the name. Namespace entries are stored in the order they occur in the source code.
|
||||
bool getTokenRange(std::vector<Token> keywords,UnorderedBlocks &tokenRange, OrderedBlocks &tokenRangeInv, bool fullName, VariableScopes *blocks);
|
||||
/// Global variables are the variables that are not inside a function or UDT
|
||||
void fixGlobalVariables();
|
||||
/// Creates the definition maps for UDTs, functions, their variables and global variables
|
||||
void getDefinitions();
|
||||
void loadGlobalDefinitions(Scopes tokenRangeSet, std::vector<IdentifierType> identifierTypes, Variables &variables);
|
||||
void loadVariableDefinitions(UnorderedBlocks tokenRangeMap, Token delimiter1, Token delimiter2, std::vector<IdentifierType> identifierTypes, bool isArgument, VariableMap &variableMap);
|
||||
void loadTypeDefinitions(UnorderedBlocks tokenRangeMap, std::vector<IdentifierType> identifierTypes, Definitions &types);
|
||||
std::string getArgumentTypeName(i32 rangeStart, Token delimiter2);
|
||||
std::string getVariableTypeName();
|
||||
/// Append the variable definitions of the parent to the child
|
||||
void appendInheritances();
|
||||
void recurseInheritances(std::string name);
|
||||
///Loads a map of identifiers to their token id instances
|
||||
void loadInstances();
|
||||
/// Replace auto with the actual type for template arguments and function parameters
|
||||
void fixAutos();
|
||||
void resolveAutos(VariableMap &variableMap, UnorderedBlocks &tokenRange);
|
||||
/// Chains are sequences of identifiers separated by scope resolution or dot operators.
|
||||
void fixChains();
|
||||
bool colorSeparatorScopeChain();
|
||||
bool colorOperatorDotChain();
|
||||
/// Returns the next/previous valid source code line
|
||||
u32 nextLine(u32 line);
|
||||
u32 previousLine(u32 line);
|
||||
/// Loads the source code and calculates the first token index of each line
|
||||
void loadText();
|
||||
/// Used to obtain the color to be applied.
|
||||
TextEditor::PaletteIndex getPaletteIndex(Token::Literal *literal);
|
||||
/// The complement of a set is also known as its inverse
|
||||
void invertGlobalTokenRange();
|
||||
/// Starting at the identifier, it tracks all the scope resolution and dot operators and returns the full chain without arrays, templates, pointers,...
|
||||
bool getFullName(std::string &identifierName, std::vector<Identifier *> &identifiers, bool preserveCurr = true);
|
||||
/// Returns the identifier value.
|
||||
bool getIdentifierName(std::string &identifierName, Identifier *identifier);
|
||||
/// Adds namespaces to the full name if they exist
|
||||
bool getQualifiedName(std::string &identifierName, std::vector<Identifier *> &identifiers, bool useDefinitions = false, bool preserveCurr = true);
|
||||
/// As it moves forward it loads the result to the argument. Used by getFullName
|
||||
bool forwardIdentifierName(std::string &identifierName, std::vector<Identifier *> &identifiers, bool preserveCurr = true);
|
||||
/// Takes as input the full name and returns the type of the last element.
|
||||
bool resolveIdentifierType(Definition &result, std::string identifierName);
|
||||
/// like previous functions but returns the type of the variable that is a member of a UDT
|
||||
std::string findIdentifierTypeStr(const std::string &identifierName, std::string context="");
|
||||
IdentifierType findIdentifierType(const std::string &identifierName, std::string context);
|
||||
/// If context is empty search for the variable, if it isnt use the variable map.
|
||||
bool findOrContains(std::string &context, UnorderedBlocks tokenRange, VariableMap variableMap);
|
||||
/// Search for instances inside some block
|
||||
void setBlockInstancesColor(const std::string &name, const Definition &definition, const Interval &block);
|
||||
/// Convenience functions.
|
||||
void skipAttribute();
|
||||
void skipArray(i32 maxSkipCount, bool forward = true);
|
||||
void skipTemplate(i32 maxSkipCount, bool forward = true);
|
||||
void skipDelimiters(i32 maxSkipCount, Token delimiter[2], i8 increment);
|
||||
void skipToken(Token token, i8 step=1);
|
||||
/// from given or current names find the corresponding definition
|
||||
bool findIdentifierDefinition(Definition &result, const std::string &optionalIdentifierName = "", std::string optionalName = "", bool optional = false);
|
||||
/// To deal with the Parent keyword
|
||||
std::optional<Definition> setChildrenTypes();
|
||||
bool findParentTypes(std::vector<std::string> &parentTypes, const std::string &optionalName="");
|
||||
bool findAllParentTypes(std::vector<std::string> &parentTypes, std::vector<Identifier *> &identifiers, std::string &optionalFullName);
|
||||
bool tryParentType(const std::string &parentType, std::string &variableName, std::optional<Definition> &result, std::vector<Identifier *> &identifiers);
|
||||
/// Convenience function
|
||||
bool isTokenIdValid(i32 tokenId);
|
||||
bool isLocationValid(Location location);
|
||||
/// Returns the name of the context where the current or given token is located
|
||||
bool findScope(std::string &name, const UnorderedBlocks &map, i32 optionalTokenId=-1);
|
||||
/// Returns the name of the namespace where the current or given token is located
|
||||
bool findNamespace(std::string &nameSpace, i32 optionalTokenId=-1);
|
||||
/// Calculate the source code, line and column numbers of a token index
|
||||
pl::core::Location getLocation(i32 tokenId);
|
||||
/// Calculate the token index of a source code, line and column numbers
|
||||
i32 getTokenId(pl::core::Location location);
|
||||
/// Calculate the function or template argument position from token indices
|
||||
i32 getArgumentNumber(i32 start,i32 arg);
|
||||
/// Calculate the token index of a function or template argument position
|
||||
void getTokenIdForArgument(i32 start, i32 argNumber, Token delimiter);
|
||||
///Creates a map from function name to argument type
|
||||
void linkAttribute();
|
||||
/// Comment and strings usethese function to determine their coordinates
|
||||
template<typename T> TextEditor::Coordinates commentCoordinates(Token *token);
|
||||
TextEditor::Coordinates stringCoordinates();
|
||||
/// Returns the number of tasks highlighting code. Shouldn't be > 1
|
||||
i32 getRunningColorizers() {
|
||||
return m_runningColorizers;
|
||||
}
|
||||
|
||||
enum class HighlightStage {
|
||||
Starting,
|
||||
NamespaceTokenRanges,
|
||||
UDTTokenRanges,
|
||||
FunctionTokenRanges,
|
||||
GlobalTokenRanges,
|
||||
FixGlobalVariables,
|
||||
SetInitialColors,
|
||||
LoadInstances,
|
||||
AttributeTokenRanges,
|
||||
Definitions,
|
||||
FixAutos,
|
||||
FixChains,
|
||||
ExcludedLocations,
|
||||
ColorRemainingTokens,
|
||||
SetRequestedIdentifierColors,
|
||||
Stage1,
|
||||
Stage2,
|
||||
Stage3,
|
||||
Stage4,
|
||||
Stage5,
|
||||
Stage6,
|
||||
Stage7,
|
||||
Stage8,
|
||||
Stage9,
|
||||
Stage10,
|
||||
Stage11,
|
||||
};
|
||||
|
||||
HighlightStage m_highlightStage = HighlightStage::Starting;
|
||||
|
||||
/// The following functions were copied from the parser and some were modified
|
||||
|
||||
template<typename T>
|
||||
T *getValue(const i32 index) {
|
||||
return const_cast<T*>(std::get_if<T>(&m_curr[index].value));
|
||||
}
|
||||
|
||||
void next(i32 count = 1) {
|
||||
if (count == 0)
|
||||
return;
|
||||
i32 id = getTokenId(m_curr->location);
|
||||
i32 maxChange;
|
||||
if (count > 0)
|
||||
maxChange = std::min(count,static_cast<i32>(m_tokens.size() - id));
|
||||
else
|
||||
maxChange = -std::min(-count,id);
|
||||
m_curr += maxChange;
|
||||
}
|
||||
constexpr static u32 Normal = 0;
|
||||
constexpr static u32 Not = 1;
|
||||
|
||||
bool begin() {
|
||||
m_originalPosition = m_curr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void partBegin() {
|
||||
m_partOriginalPosition = m_curr;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
m_curr = m_originalPosition;
|
||||
}
|
||||
|
||||
void partReset() {
|
||||
m_curr = m_partOriginalPosition;
|
||||
}
|
||||
|
||||
bool resetIfFailed(const bool value) {
|
||||
if (!value) reset();
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
template<auto S = Normal>
|
||||
bool sequenceImpl() {
|
||||
if constexpr (S == Normal)
|
||||
return true;
|
||||
else if constexpr (S == Not)
|
||||
return false;
|
||||
else
|
||||
std::unreachable();
|
||||
}
|
||||
|
||||
template<auto S = Normal>
|
||||
bool matchOne(const Token &token) {
|
||||
if constexpr (S == Normal) {
|
||||
if (!peek(token)) {
|
||||
partReset();
|
||||
return false;
|
||||
}
|
||||
|
||||
next();
|
||||
return true;
|
||||
} else if constexpr (S == Not) {
|
||||
if (!peek(token))
|
||||
return true;
|
||||
|
||||
next();
|
||||
partReset();
|
||||
return false;
|
||||
} else
|
||||
std::unreachable();
|
||||
}
|
||||
|
||||
template<auto S = Normal>
|
||||
bool sequenceImpl(const auto &... args) {
|
||||
return (matchOne<S>(args) && ...);
|
||||
}
|
||||
|
||||
template<auto S = Normal>
|
||||
bool sequence(const Token &token, const auto &... args) {
|
||||
partBegin();
|
||||
return sequenceImpl<S>(token, args...);
|
||||
}
|
||||
|
||||
bool isValid() {
|
||||
Token token;
|
||||
try {
|
||||
token = m_curr[0];
|
||||
}
|
||||
catch (const std::out_of_range &e) {
|
||||
auto t = e.what();
|
||||
if (t == nullptr)
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
if (!isLocationValid(token.location))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool peek(const Token &token, const i32 index = 0) {
|
||||
if (!isValid())
|
||||
return false;
|
||||
i32 id = getTokenId(m_curr->location);
|
||||
if (id+index < 0 || id+index >= (i32)m_tokens.size())
|
||||
return false;
|
||||
return m_curr[index].type == token.type && m_curr[index] == token.value;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <TextEditor.h>
|
||||
#include <popups/popup_file_chooser.hpp>
|
||||
#include <content/text_highlighting/pattern_language.hpp>
|
||||
|
||||
namespace pl::ptrn { class Pattern; }
|
||||
|
||||
@@ -69,6 +70,30 @@ namespace hex::plugin::builtin {
|
||||
~ViewPatternEditor() override;
|
||||
|
||||
void drawAlwaysVisibleContent() override;
|
||||
std::unique_ptr<pl::PatternLanguage> *getPatternLanguage() {
|
||||
return &m_editorRuntime;
|
||||
}
|
||||
|
||||
TextEditor &getTextEditor() {
|
||||
return m_textEditor;
|
||||
}
|
||||
|
||||
bool getChangesWereParsed() const {
|
||||
return m_changesWereParsed;
|
||||
}
|
||||
|
||||
u32 getRunningParsers () const {
|
||||
return m_runningParsers;
|
||||
}
|
||||
|
||||
u32 getRunningEvaluators () const {
|
||||
return m_runningEvaluators;
|
||||
}
|
||||
|
||||
void setChangesWereParsed(bool changesWereParsed) {
|
||||
m_changesWereParsed = changesWereParsed;
|
||||
}
|
||||
|
||||
void drawContent() override;
|
||||
[[nodiscard]] ImGuiWindowFlags getWindowFlags() const override {
|
||||
return ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse;
|
||||
@@ -234,6 +259,7 @@ namespace hex::plugin::builtin {
|
||||
std::atomic<u32> m_runningEvaluators = 0;
|
||||
std::atomic<u32> m_runningParsers = 0;
|
||||
|
||||
bool m_changesWereParsed = false;
|
||||
PerProvider<bool> m_hasUnevaluatedChanges;
|
||||
std::chrono::time_point<std::chrono::steady_clock> m_lastEditorChangeTime;
|
||||
|
||||
@@ -308,6 +334,7 @@ namespace hex::plugin::builtin {
|
||||
static inline u32 m_replaceHistorySize = 0;
|
||||
static inline u32 m_replaceHistoryIndex = 0;
|
||||
|
||||
TextHighlighter m_textHighlighter = TextHighlighter(this,&this->m_editorRuntime);
|
||||
private:
|
||||
void drawConsole(ImVec2 size);
|
||||
void drawEnvVars(ImVec2 size, std::list<EnvVar> &envVars);
|
||||
|
||||
@@ -147,27 +147,51 @@
|
||||
"title-text": "#E5E5E5FF"
|
||||
},
|
||||
"text-editor": {
|
||||
"attribute": "#FFFF00FF",
|
||||
"background": "#000080FF",
|
||||
"multi-line-comment": "#404040FF",
|
||||
"breakpoint": "#FF200080",
|
||||
"known-identifier": "#4DC69BFF",
|
||||
"calculated-pointer": "#FFFF00FF",
|
||||
"char-literal": "#008080FF",
|
||||
"comment": "#808080FF",
|
||||
"current-line-edge": "#00000040",
|
||||
"current-line-fill": "#00000040",
|
||||
"current-line-fill-inactive": "#80808040",
|
||||
"cursor": "#FF8000FF",
|
||||
"debug-text": "#8A8A8AFF",
|
||||
"default": "#FFFF00FF",
|
||||
"default-text": "#FFFF00FF",
|
||||
"preprocessor": "#7FBF00FF",
|
||||
"doc-block-comment": "#206020FF",
|
||||
"doc-comment": "#206020FF",
|
||||
"doc-global-comment": "#206020FF",
|
||||
"error-marker": "#FF0000A0",
|
||||
"error-text": "#FF200080",
|
||||
"function": "#FFFF00FF",
|
||||
"function-parameter": "#FFFF00FF",
|
||||
"function-variable": "#FFFF00FF",
|
||||
"global-variable": "#FFFF00FF",
|
||||
"identifier": "#FFFF00FF",
|
||||
"keyword": "#00FFFFFF",
|
||||
"known-identifier": "#FFFFFFFF",
|
||||
"line-number": "#008080FF",
|
||||
"multi-line-comment": "#404040FF",
|
||||
"local-variable": "#FFFF00FF",
|
||||
"namespace": "#FFFF00FF",
|
||||
"number": "#00FF00FF",
|
||||
"preproc-identifier": "#FF00FFFF",
|
||||
"preprocessor": "#008000FF",
|
||||
"punctuation": "#FFFFFFFF",
|
||||
"punctuation": "#FFFF00FF",
|
||||
"pattern-variable": "#FFFF00FF",
|
||||
"placed-variable": "#FFFF00FF",
|
||||
"preprocessor-deactivated": "#4F4F4F45",
|
||||
"preproc-identifier": "#7FBF00FF",
|
||||
"selection": "*#00FFFF80",
|
||||
"string": "#008080FF"
|
||||
"separator": "#FFFF00FF",
|
||||
"string": "#008080FF",
|
||||
"template-variable": "#FFFF00FF",
|
||||
"typedef": "#FFFF00FF",
|
||||
"unknown-identifier": "#FC2C2CFE",
|
||||
"user-defined-type": "#FFFF00FF",
|
||||
"view": "#FFFF00FF",
|
||||
"warning-text": "#FFFF00FF"
|
||||
}
|
||||
},
|
||||
"image_theme": "dark",
|
||||
|
||||
@@ -147,27 +147,51 @@
|
||||
"title-text": "#FFFFFFFF"
|
||||
},
|
||||
"text-editor": {
|
||||
"attribute": "#AAAAAAFF",
|
||||
"background": "#101010FF",
|
||||
"multi-line-comment": "#206040FF",
|
||||
"breakpoint": "#FF200040",
|
||||
"known-identifier": "#4DC69BFF",
|
||||
"calculated-pointer": "#AAAAAAFF",
|
||||
"char-literal": "#E0A070FF",
|
||||
"comment": "#206020FF",
|
||||
"current-line-edge": "#A0A0A040",
|
||||
"current-line-fill": "#00000040",
|
||||
"current-line-fill-inactive": "#80808040",
|
||||
"cursor": "#E0E0E0FF",
|
||||
"debug-text": "#8A8A8AFF",
|
||||
"default": "#7F7F7FFF",
|
||||
"default-text": "#7F7F7FFF",
|
||||
"preprocessor": "#808060FF",
|
||||
"doc-block-comment": "#206020FF",
|
||||
"doc-comment": "#206020FF",
|
||||
"doc-global-comment": "#206020FF",
|
||||
"error-marker": "#FF200080",
|
||||
"error-text": "#FF200080",
|
||||
"function": "#AAAAAAFF",
|
||||
"function-parameter": "#AAAAAAFF",
|
||||
"function-variable": "#AAAAAAFF",
|
||||
"global-variable": "#AAAAAAFF",
|
||||
"identifier": "#AAAAAAFF",
|
||||
"keyword": "#569CD6FF",
|
||||
"known-identifier": "#4DC69BFF",
|
||||
"line-number": "#007070FF",
|
||||
"multi-line-comment": "#206040FF",
|
||||
"local-variable": "#AAAAAAFF",
|
||||
"namespace": "#AAAAAAFF",
|
||||
"number": "#00FF00FF",
|
||||
"preproc-identifier": "#A040C0FF",
|
||||
"preprocessor": "#808040FF",
|
||||
"punctuation": "#FFFFFFFF",
|
||||
"punctuation": "#7F7F7FFF",
|
||||
"pattern-variable": "#AAAAAAFF",
|
||||
"placed-variable": "#AAAAAAFF",
|
||||
"preprocessor-deactivated": "#4F4F4F45",
|
||||
"preproc-identifier": "#808060FF",
|
||||
"selection": "*#2060A080",
|
||||
"string": "#E07070FF"
|
||||
"separator": "#7F7F7FFF",
|
||||
"string": "#E07070FF",
|
||||
"template-variable": "#AAAAAAFF",
|
||||
"typedef": "#AAAAAAFF",
|
||||
"unknown-identifier": "#FC2C2CFE",
|
||||
"user-defined-type": "#AAAAAAFF",
|
||||
"view": "#AAAAAAFF",
|
||||
"warning-text": "#FFFF00FF"
|
||||
}
|
||||
},
|
||||
"image_theme": "dark",
|
||||
|
||||
@@ -147,27 +147,50 @@
|
||||
"title-text": "#000000FF"
|
||||
},
|
||||
"text-editor": {
|
||||
"attribute": "#404040FF",
|
||||
"background": "#FFFFFFFF",
|
||||
"multi-line-comment": "#205040FF",
|
||||
"breakpoint": "#FF200080",
|
||||
"known-identifier": "#106060FF",
|
||||
"calculated-pointer": "#404040FF",
|
||||
"char-literal": "#704030FF",
|
||||
"comment": "#205020FF",
|
||||
"current-line-edge": "#00000040",
|
||||
"current-line-fill": "#00000040",
|
||||
"current-line-fill-inactive": "#80808040",
|
||||
"cursor": "#000000FF",
|
||||
"debug-text": "#8A8A8AFF",
|
||||
"default": "#7F7F7FFF",
|
||||
"default-text": "#7F7F7FFF",
|
||||
"preprocessor": "#6F6F5FFF",
|
||||
"doc-block-comment": "#205040FF",
|
||||
"doc-comment": "#205020FF",
|
||||
"doc-global-comment": "#205040FF",
|
||||
"error-marker": "#FF1000A0",
|
||||
"identifier": "#404040FF",
|
||||
"error-text": "#FF200080",
|
||||
"function": "#404040FF",
|
||||
"function-parameter": "#404040FF",
|
||||
"function-variable": "#404040FF",
|
||||
"global-variable": "#404040FF",
|
||||
"keyword": "#060CFFFF",
|
||||
"known-identifier": "#106060FF",
|
||||
"line-number": "#005050FF",
|
||||
"multi-line-comment": "#205040FF",
|
||||
"local-variable": "#404040FF",
|
||||
"namespace": "#404040FF",
|
||||
"number": "#008000FF",
|
||||
"preproc-identifier": "#A040C0FF",
|
||||
"preprocessor": "#606040FF",
|
||||
"punctuation": "#000000FF",
|
||||
"punctuation": "#7F7F7FFF",
|
||||
"pattern-variable": "#404040FF",
|
||||
"placed-variable": "#404040FF",
|
||||
"preprocessor-deactivated": "#4F4F4F45",
|
||||
"preproc-identifier": "#6F6F5FFF",
|
||||
"selection": "*#00006080",
|
||||
"string": "#A02020FF"
|
||||
"separator": "#7F7F7FFF",
|
||||
"string": "#A02020FF",
|
||||
"template-variable": "#404040FF",
|
||||
"typedef": "#404040FF",
|
||||
"unknown-identifier": "#FC2C2CFE",
|
||||
"user-defined-type": "#404040FF",
|
||||
"view": "#404040FF",
|
||||
"warning-text": "#FFFF00FF"
|
||||
}
|
||||
},
|
||||
"image_theme": "light",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -211,33 +211,53 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
const static ThemeManager::ColorMap TextEditorColorMap = {
|
||||
{ "default", u32(TextEditor::PaletteIndex::Default) },
|
||||
{ "keyword", u32(TextEditor::PaletteIndex::Keyword) },
|
||||
{ "number", u32(TextEditor::PaletteIndex::Number) },
|
||||
{ "string", u32(TextEditor::PaletteIndex::String) },
|
||||
{ "char-literal", u32(TextEditor::PaletteIndex::CharLiteral) },
|
||||
{ "punctuation", u32(TextEditor::PaletteIndex::Punctuation) },
|
||||
{ "preprocessor", u32(TextEditor::PaletteIndex::Preprocessor) },
|
||||
{ "identifier", u32(TextEditor::PaletteIndex::Identifier) },
|
||||
{ "known-identifier", u32(TextEditor::PaletteIndex::KnownIdentifier) },
|
||||
{ "preproc-identifier", u32(TextEditor::PaletteIndex::PreprocIdentifier) },
|
||||
{ "global-doc-comment", u32(TextEditor::PaletteIndex::GlobalDocComment) },
|
||||
{ "doc-comment", u32(TextEditor::PaletteIndex::DocComment) },
|
||||
{ "comment", u32(TextEditor::PaletteIndex::Comment) },
|
||||
{ "multi-line-comment", u32(TextEditor::PaletteIndex::MultiLineComment) },
|
||||
{ "preprocessor-deactivated", u32(TextEditor::PaletteIndex::PreprocessorDeactivated) },
|
||||
{ "background", u32(TextEditor::PaletteIndex::Background) },
|
||||
{ "cursor", u32(TextEditor::PaletteIndex::Cursor) },
|
||||
{ "selection", u32(TextEditor::PaletteIndex::Selection) },
|
||||
{ "error-marker", u32(TextEditor::PaletteIndex::ErrorMarker) },
|
||||
{ "breakpoint", u32(TextEditor::PaletteIndex::Breakpoint) },
|
||||
{ "line-number", u32(TextEditor::PaletteIndex::LineNumber) },
|
||||
{ "current-line-fill", u32(TextEditor::PaletteIndex::CurrentLineFill) },
|
||||
{ "current-line-fill-inactive", u32(TextEditor::PaletteIndex::CurrentLineFillInactive) },
|
||||
{ "current-line-edge", u32(TextEditor::PaletteIndex::CurrentLineEdge) }
|
||||
{ "attribute", u32(TextEditor::PaletteIndex::Attribute) },
|
||||
{ "background", u32(TextEditor::PaletteIndex::Background) },
|
||||
{ "breakpoint", u32(TextEditor::PaletteIndex::Breakpoint) },
|
||||
{ "calculated-pointer", u32(TextEditor::PaletteIndex::CalculatedPointer) },
|
||||
{ "char-literal", u32(TextEditor::PaletteIndex::CharLiteral) },
|
||||
{ "comment", u32(TextEditor::PaletteIndex::Comment) },
|
||||
{ "current-line-edge", u32(TextEditor::PaletteIndex::CurrentLineEdge) },
|
||||
{ "current-line-fill", u32(TextEditor::PaletteIndex::CurrentLineFill) },
|
||||
{ "current-line-fill-inactive", u32(TextEditor::PaletteIndex::CurrentLineFillInactive) },
|
||||
{ "cursor", u32(TextEditor::PaletteIndex::Cursor) },
|
||||
{ "debug-text", u32(TextEditor::PaletteIndex::DebugText) },
|
||||
{ "default", u32(TextEditor::PaletteIndex::Default) },
|
||||
{ "default-text", u32(TextEditor::PaletteIndex::DefaultText) },
|
||||
{ "doc-block-comment", u32(TextEditor::PaletteIndex::DocBlockComment) },
|
||||
{ "doc-comment", u32(TextEditor::PaletteIndex::DocComment) },
|
||||
{ "doc-global-comment", u32(TextEditor::PaletteIndex::GlobalDocComment) },
|
||||
{ "error-marker", u32(TextEditor::PaletteIndex::ErrorMarker) },
|
||||
{ "error-text", u32(TextEditor::PaletteIndex::ErrorText) },
|
||||
{ "function", u32(TextEditor::PaletteIndex::Function) },
|
||||
{ "function-parameter", u32(TextEditor::PaletteIndex::FunctionParameter) },
|
||||
{ "function-variable", u32(TextEditor::PaletteIndex::FunctionVariable) },
|
||||
{ "global-variable", u32(TextEditor::PaletteIndex::GlobalVariable) },
|
||||
{ "identifier" , u32(TextEditor::PaletteIndex::Identifier) },
|
||||
{ "keyword", u32(TextEditor::PaletteIndex::Keyword) },
|
||||
{ "known-identifier", u32(TextEditor::PaletteIndex::BuiltInType) },
|
||||
{ "line-number", u32(TextEditor::PaletteIndex::LineNumber) },
|
||||
{ "local-variable", u32(TextEditor::PaletteIndex::LocalVariable) },
|
||||
{ "multi-line-comment", u32(TextEditor::PaletteIndex::BlockComment) },
|
||||
{ "namespace", u32(TextEditor::PaletteIndex::NameSpace) },
|
||||
{ "number", u32(TextEditor::PaletteIndex::NumericLiteral) },
|
||||
{ "pattern-variable", u32(TextEditor::PaletteIndex::PatternVariable) },
|
||||
{ "placed-variable", u32(TextEditor::PaletteIndex::PlacedVariable) },
|
||||
{ "preprocessor", u32(TextEditor::PaletteIndex::Directive) },
|
||||
{ "preprocessor-deactivated", u32(TextEditor::PaletteIndex::PreprocessorDeactivated) },
|
||||
{ "preproc-identifier", u32(TextEditor::PaletteIndex::PreprocIdentifier) },
|
||||
{ "punctuation", u32(TextEditor::PaletteIndex::Operator) },
|
||||
{ "selection", u32(TextEditor::PaletteIndex::Selection) },
|
||||
{ "separator", u32(TextEditor::PaletteIndex::Separator) },
|
||||
{ "string", u32(TextEditor::PaletteIndex::StringLiteral) },
|
||||
{ "template-variable", u32(TextEditor::PaletteIndex::TemplateArgument) },
|
||||
{ "typedef", u32(TextEditor::PaletteIndex::TypeDef) },
|
||||
{ "unknown-identifier", u32(TextEditor::PaletteIndex::UnkIdentifier) },
|
||||
{ "user-defined-type", u32(TextEditor::PaletteIndex::UserDefinedType) },
|
||||
{ "view", u32(TextEditor::PaletteIndex::View) },
|
||||
{ "warning-text", u32(TextEditor::PaletteIndex::WarningText) }
|
||||
};
|
||||
|
||||
ThemeManager::addThemeHandler("text-editor", TextEditorColorMap,
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
#include <hex/api/events/requests_interaction.hpp>
|
||||
|
||||
#include <pl/patterns/pattern.hpp>
|
||||
#include <pl/core/preprocessor.hpp>
|
||||
#include <pl/core/parser.hpp>
|
||||
#include <pl/core/lexer.hpp>
|
||||
#include <pl/core/ast/ast_node_variable_decl.hpp>
|
||||
#include <pl/core/ast/ast_node_builtin_type.hpp>
|
||||
|
||||
@@ -47,7 +46,7 @@ namespace hex::plugin::builtin {
|
||||
static TextEditor::LanguageDefinition langDef;
|
||||
if (!initialized) {
|
||||
constexpr static std::array keywords = {
|
||||
"using", "struct", "union", "enum", "bitfield", "be", "le", "if", "else", "match", "false", "true", "this", "parent", "addressof", "sizeof", "typenameof", "$", "while", "for", "fn", "return", "break", "continue", "namespace", "in", "out", "ref", "null", "const", "unsigned", "signed", "try", "catch", "import", "as", "from"
|
||||
"using", "struct", "union", "enum", "bitfield", "be", "le", "if", "else", "match", "false", "true", "this", "parent", "addressof", "sizeof", "typenameof", "while", "for", "fn", "return", "break", "continue", "namespace", "in", "out", "ref", "null", "const", "unsigned", "signed", "try", "catch", "import", "as", "from"
|
||||
};
|
||||
for (auto &k : keywords)
|
||||
langDef.mKeywords.insert(k);
|
||||
@@ -60,8 +59,15 @@ namespace hex::plugin::builtin {
|
||||
id.mDeclaration = "";
|
||||
langDef.mIdentifiers.insert(std::make_pair(std::string(name), id));
|
||||
}
|
||||
|
||||
langDef.mTokenize = [](const char *inBegin, const char *inEnd, const char *&outBegin, const char *&outEnd, TextEditor::PaletteIndex &paletteIndex) -> bool {
|
||||
constexpr static std::array directives = {
|
||||
"include", "define", "ifdef", "ifndef", "endif", "undef", "pragma", "error"
|
||||
};
|
||||
for (const auto name : directives) {
|
||||
TextEditor::Identifier id;
|
||||
id.mDeclaration = "";
|
||||
langDef.mPreprocIdentifiers.insert(std::make_pair(std::string(name), id));
|
||||
}
|
||||
langDef.mTokenize = [](std::string::const_iterator inBegin, std::string::const_iterator inEnd, std::string::const_iterator &outBegin, std::string::const_iterator &outEnd, TextEditor::PaletteIndex &paletteIndex) -> bool {
|
||||
paletteIndex = TextEditor::PaletteIndex::Max;
|
||||
|
||||
while (inBegin < inEnd && isascii(*inBegin) && std::isblank(*inBegin))
|
||||
@@ -74,13 +80,16 @@ namespace hex::plugin::builtin {
|
||||
} else if (TokenizeCStyleIdentifier(inBegin, inEnd, outBegin, outEnd)) {
|
||||
paletteIndex = TextEditor::PaletteIndex::Identifier;
|
||||
} else if (TokenizeCStyleNumber(inBegin, inEnd, outBegin, outEnd)) {
|
||||
paletteIndex = TextEditor::PaletteIndex::Number;
|
||||
paletteIndex = TextEditor::PaletteIndex::NumericLiteral;
|
||||
} else if (TokenizeCStyleCharacterLiteral(inBegin, inEnd, outBegin, outEnd)) {
|
||||
paletteIndex = TextEditor::PaletteIndex::CharLiteral;
|
||||
} else if (TokenizeCStyleString(inBegin, inEnd, outBegin, outEnd)) {
|
||||
paletteIndex = TextEditor::PaletteIndex::String;
|
||||
paletteIndex = TextEditor::PaletteIndex::StringLiteral;
|
||||
} else if (TokenizeCStyleSeparator(inBegin, inEnd, outBegin, outEnd)) {
|
||||
paletteIndex = TextEditor::PaletteIndex::Separator;
|
||||
} else if (TokenizeCStyleOperator(inBegin, inEnd, outBegin, outEnd)) {
|
||||
paletteIndex = TextEditor::PaletteIndex::Operator;
|
||||
}
|
||||
|
||||
return paletteIndex != TextEditor::PaletteIndex::Max;
|
||||
};
|
||||
|
||||
@@ -92,8 +101,9 @@ namespace hex::plugin::builtin {
|
||||
langDef.mAutoIndentation = true;
|
||||
langDef.mPreprocChar = '#';
|
||||
|
||||
langDef.mGlobalDocComment = "/*!";
|
||||
langDef.mDocComment = "/**";
|
||||
langDef.mGlobalDocComment = "/*!";
|
||||
langDef.mBlockDocComment = "/**";
|
||||
langDef.mDocComment = "///";
|
||||
|
||||
langDef.mName = "Pattern Language";
|
||||
|
||||
@@ -107,15 +117,16 @@ namespace hex::plugin::builtin {
|
||||
static bool initialized = false;
|
||||
static TextEditor::LanguageDefinition langDef;
|
||||
if (!initialized) {
|
||||
langDef.mTokenize = [](const char *inBegin, const char *inEnd, const char *&outBegin, const char *&outEnd, TextEditor::PaletteIndex &paletteIndex) -> bool {
|
||||
if (std::string_view(inBegin).starts_with("D: "))
|
||||
paletteIndex = TextEditor::PaletteIndex::Comment;
|
||||
else if (std::string_view(inBegin).starts_with("I: "))
|
||||
paletteIndex = TextEditor::PaletteIndex::Default;
|
||||
else if (std::string_view(inBegin).starts_with("W: "))
|
||||
paletteIndex = TextEditor::PaletteIndex::Preprocessor;
|
||||
else if (std::string_view(inBegin).starts_with("E: "))
|
||||
paletteIndex = TextEditor::PaletteIndex::ErrorMarker;
|
||||
langDef.mTokenize = [](std::string::const_iterator inBegin, std::string::const_iterator inEnd, std::string::const_iterator &outBegin, std::string::const_iterator &outEnd, TextEditor::PaletteIndex &paletteIndex) -> bool {
|
||||
std::string_view inView(inBegin, inEnd);
|
||||
if (inView.starts_with("D: "))
|
||||
paletteIndex = TextEditor::PaletteIndex::DefaultText;
|
||||
else if (inView.starts_with("I: "))
|
||||
paletteIndex = TextEditor::PaletteIndex::DebugText;
|
||||
else if (inView.starts_with("W: "))
|
||||
paletteIndex = TextEditor::PaletteIndex::WarningText;
|
||||
else if (inView.starts_with("E: "))
|
||||
paletteIndex = TextEditor::PaletteIndex::ErrorText;
|
||||
else
|
||||
paletteIndex = TextEditor::PaletteIndex::Max;
|
||||
|
||||
@@ -583,14 +594,18 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
}
|
||||
|
||||
if (m_textEditor.get(provider).IsTextChanged() && !m_hasUnevaluatedChanges.get(provider)) {
|
||||
m_hasUnevaluatedChanges.get(provider) = true;
|
||||
if (m_textEditor.get(provider).IsTextChanged()) {
|
||||
m_textEditor.get(provider).SetTextChanged(false);
|
||||
if (!m_hasUnevaluatedChanges.get(provider) ) {
|
||||
m_hasUnevaluatedChanges.get(provider) = true;
|
||||
m_changesWereParsed = false;
|
||||
}
|
||||
m_lastEditorChangeTime = std::chrono::steady_clock::now();
|
||||
ImHexApi::Provider::markDirty();
|
||||
}
|
||||
|
||||
if (m_hasUnevaluatedChanges.get(provider) && m_runningEvaluators == 0 && m_runningParsers == 0) {
|
||||
if ((std::chrono::steady_clock::now() - m_lastEditorChangeTime) > std::chrono::seconds(1LL)) {
|
||||
if (m_hasUnevaluatedChanges.get(provider) && m_runningEvaluators == 0 && m_runningParsers == 0 &&
|
||||
(std::chrono::steady_clock::now() - m_lastEditorChangeTime) > std::chrono::seconds(1ll)) {
|
||||
|
||||
auto code = m_textEditor.get(provider).GetText();
|
||||
EventPatternEditorChanged::post(code);
|
||||
@@ -602,13 +617,21 @@ namespace hex::plugin::builtin {
|
||||
m_triggerAutoEvaluate = true;
|
||||
});
|
||||
m_hasUnevaluatedChanges.get(provider) = false;
|
||||
m_textEditor.get(provider).SetTextChanged();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_triggerAutoEvaluate.exchange(false)) {
|
||||
this->evaluatePattern(m_textEditor.get(provider).GetText(), provider);
|
||||
}
|
||||
if (m_textHighlighter.m_needsToUpdateColors && m_changesWereParsed && (m_runningParsers + m_runningEvaluators == 0)) {
|
||||
TaskHolder taskHolder;
|
||||
if (m_textHighlighter.getRunningColorizers() == 0) {
|
||||
m_textHighlighter.m_needsToUpdateColors = false;
|
||||
m_changesWereParsed = false;
|
||||
taskHolder = TaskManager::createBackgroundTask("HighlightSourceCode", [this](auto &) { m_textHighlighter.highlightSourceCode(); });
|
||||
} else {
|
||||
taskHolder.interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_dangerousFunctionCalled && !ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopup)) {
|
||||
@@ -1228,7 +1251,7 @@ namespace hex::plugin::builtin {
|
||||
const std::string label { "##" + name };
|
||||
|
||||
if (pl::core::Token::isSigned(variable.type)) {
|
||||
i64 value = i64(hex::get_or<i128>(variable.value, 0));
|
||||
i64 value = i64(hex::get_or<i128>(variable.value, 0ll));
|
||||
if (ImGui::InputScalar(label.c_str(), ImGuiDataType_S64, &value))
|
||||
m_hasUnevaluatedChanges.get(provider) = true;
|
||||
variable.value = i128(value);
|
||||
@@ -1495,7 +1518,7 @@ namespace hex::plugin::builtin {
|
||||
};
|
||||
|
||||
TextEditor::ErrorMarkers errorMarkers;
|
||||
if (!(*m_callStack)->empty()) {
|
||||
if (*m_callStack != nullptr && !(*m_callStack)->empty()) {
|
||||
for (const auto &frame : **m_callStack | std::views::reverse) {
|
||||
auto location = frame.node->getLocation();
|
||||
std::string message;
|
||||
@@ -1701,7 +1724,7 @@ namespace hex::plugin::builtin {
|
||||
const bool shiftHeld = ImGui::GetIO().KeyShift;
|
||||
ImGui::ColorButton(pattern->getVariableName().c_str(), ImColor(pattern->getColor()), ImGuiColorEditFlags_AlphaOpaque);
|
||||
ImGui::SameLine(0, 10);
|
||||
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::KnownIdentifier)], "{} ", pattern->getFormattedName());
|
||||
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::BuiltInType)], "{} ", pattern->getFormattedName());
|
||||
ImGui::SameLine(0, 5);
|
||||
ImGuiExt::TextFormatted("{}", pattern->getDisplayName());
|
||||
ImGui::SameLine();
|
||||
@@ -1844,6 +1867,7 @@ namespace hex::plugin::builtin {
|
||||
m_textEditor.get(provider).SetText(code, true);
|
||||
m_sourceCode.get(provider) = code;
|
||||
|
||||
m_textHighlighter.m_needsToUpdateColors = false;
|
||||
TaskManager::createBackgroundTask("hex.builtin.task.parsing_pattern", [this, code, provider](auto&) { this->parsePattern(code, provider); });
|
||||
}
|
||||
}
|
||||
@@ -1885,6 +1909,8 @@ namespace hex::plugin::builtin {
|
||||
patternVariables = std::move(oldPatternVariables);
|
||||
}
|
||||
|
||||
m_textHighlighter.m_needsToUpdateColors = true;
|
||||
m_changesWereParsed = true;
|
||||
m_runningParsers -= 1;
|
||||
}
|
||||
|
||||
@@ -2039,6 +2065,7 @@ namespace hex::plugin::builtin {
|
||||
m_textEditor.get(provider).SetText(code);
|
||||
m_sourceCode.get(provider) = code;
|
||||
m_hasUnevaluatedChanges.get(provider) = true;
|
||||
m_textHighlighter.m_needsToUpdateColors = false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::onChange("hex.builtin.setting.general", "hex.builtin.setting.general.sync_pattern_source", [this](const ContentRegistry::Settings::SettingsValue &value) {
|
||||
@@ -2098,7 +2125,9 @@ namespace hex::plugin::builtin {
|
||||
m_cursorNeedsUpdate.get(newProvider) = true;
|
||||
m_consoleCursorNeedsUpdate.get(newProvider) = true;
|
||||
m_textEditor.get(newProvider).SetTextChanged(false);
|
||||
m_hasUnevaluatedChanges.get(newProvider) = true;
|
||||
}
|
||||
m_textHighlighter.m_needsToUpdateColors = false;
|
||||
|
||||
});
|
||||
|
||||
@@ -2327,7 +2356,7 @@ namespace hex::plugin::builtin {
|
||||
m_textEditor.get(provider).SetText(sourceCode);
|
||||
|
||||
m_hasUnevaluatedChanges.get(provider) = true;
|
||||
|
||||
m_textHighlighter.m_needsToUpdateColors = false;
|
||||
return true;
|
||||
},
|
||||
.store = [this](prv::Provider *provider, const std::fs::path &basePath, const Tar &tar) {
|
||||
|
||||
@@ -523,7 +523,7 @@ namespace hex::ui {
|
||||
|
||||
// Draw type column
|
||||
ImGui::TableNextColumn();
|
||||
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::KnownIdentifier)], "{}", pattern.getFormattedName().empty() ? pattern.getTypeName() : pattern.getFormattedName());
|
||||
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::BuiltInType)], "{}", pattern.getFormattedName().empty() ? pattern.getTypeName() : pattern.getFormattedName());
|
||||
}
|
||||
|
||||
void PatternDrawer::closeTreeNode(bool inlined) const {
|
||||
@@ -550,19 +550,19 @@ namespace hex::ui {
|
||||
if (dynamic_cast<pl::ptrn::PatternBitfieldFieldSigned*>(&pattern) != nullptr) {
|
||||
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::Keyword)], "signed");
|
||||
ImGui::SameLine();
|
||||
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::KnownIdentifier)], pattern.getBitSize() == 1 ? "bit" : "bits");
|
||||
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::BuiltInType)], pattern.getBitSize() == 1 ? "bit" : "bits");
|
||||
} else if (dynamic_cast<pl::ptrn::PatternBitfieldFieldEnum*>(&pattern) != nullptr) {
|
||||
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::Keyword)], "enum");
|
||||
ImGui::SameLine();
|
||||
ImGui::TextUnformatted(pattern.getTypeName().c_str());
|
||||
} else if (dynamic_cast<pl::ptrn::PatternBitfieldFieldBoolean*>(&pattern) != nullptr) {
|
||||
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::KnownIdentifier)], "bool");
|
||||
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::BuiltInType)], "bool");
|
||||
ImGui::SameLine();
|
||||
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::KnownIdentifier)], "bit");
|
||||
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::BuiltInType)], "bit");
|
||||
} else {
|
||||
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::Keyword)], "unsigned");
|
||||
ImGui::SameLine();
|
||||
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::KnownIdentifier)], pattern.getBitSize() == 1 ? "bit" : "bits");
|
||||
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::BuiltInType)], pattern.getBitSize() == 1 ? "bit" : "bits");
|
||||
}
|
||||
|
||||
if (!this->isEditingPattern(pattern)) {
|
||||
@@ -792,7 +792,7 @@ namespace hex::ui {
|
||||
drawOffsetColumns(pattern);
|
||||
drawSizeColumn(pattern);
|
||||
ImGui::TableNextColumn();
|
||||
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::KnownIdentifier)], "{}", pattern.getFormattedName());
|
||||
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::BuiltInType)], "{}", pattern.getFormattedName());
|
||||
drawValueColumn(pattern);
|
||||
drawCommentColumn(pattern);
|
||||
}
|
||||
@@ -1038,12 +1038,12 @@ namespace hex::ui {
|
||||
drawSizeColumn(pattern);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::KnownIdentifier)], "{0}", pattern.getTypeName());
|
||||
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::BuiltInType)], "{0}", pattern.getTypeName());
|
||||
ImGui::SameLine(0, 0);
|
||||
|
||||
ImGui::TextUnformatted("[");
|
||||
ImGui::SameLine(0, 0);
|
||||
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::Number)], "{0}", iterable.getEntryCount());
|
||||
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::NumericLiteral)], "{0}", iterable.getEntryCount());
|
||||
ImGui::SameLine(0, 0);
|
||||
ImGui::TextUnformatted("]");
|
||||
|
||||
@@ -1106,12 +1106,12 @@ namespace hex::ui {
|
||||
ImGui::TableNextColumn();
|
||||
ImGuiExt::TextFormatted("{0} {1}", chunkSize, chunkSize == 1 ? "byte" : "bytes");
|
||||
ImGui::TableNextColumn();
|
||||
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::KnownIdentifier)], "{0}", pattern.getTypeName());
|
||||
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::BuiltInType)], "{0}", pattern.getTypeName());
|
||||
ImGui::SameLine(0, 0);
|
||||
|
||||
ImGui::TextUnformatted("[");
|
||||
ImGui::SameLine(0, 0);
|
||||
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::Number)], "{0}", endIndex - i);
|
||||
ImGuiExt::TextFormattedColored(TextEditor::GetPalette()[u32(TextEditor::PaletteIndex::NumericLiteral)], "{0}", endIndex - i);
|
||||
ImGui::SameLine(0, 0);
|
||||
ImGui::TextUnformatted("]");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user