mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-28 07:47:03 -05:00
feat: added matched bracket highlights + updating pattern language library (#2335)
Added clion-like bracket matching feature with shortcut to go to the other one. Also improved some cumbersome repeated function call. Added support for using negative indices in coordinates so -1 is the last line or column, -2 the previous, etc.. Pattern library has fixes for column errors being incorrectly set for lines containing tabs that are not replaced by 4 spaces.
This commit is contained in:
2
lib/external/libwolv
vendored
2
lib/external/libwolv
vendored
Submodule lib/external/libwolv updated: 3c7965a3fd...0181fd6ffd
2
lib/external/pattern_language
vendored
2
lib/external/pattern_language
vendored
Submodule lib/external/pattern_language updated: 9954c25d9c...7cbc1ac7f8
@@ -235,6 +235,7 @@ public:
|
||||
bool mGlobalDocComment : 1;
|
||||
bool mDeactivated : 1;
|
||||
bool mPreprocessor : 1;
|
||||
bool mMatchedBracket : 1;
|
||||
};
|
||||
union Flags {
|
||||
Flags(char value) : mValue(value) {}
|
||||
@@ -244,6 +245,8 @@ public:
|
||||
};
|
||||
constexpr static char InComment = 31;
|
||||
|
||||
int GetCharacterColumn(int aIndex) const;
|
||||
|
||||
class LineIterator {
|
||||
public:
|
||||
strConstIter mCharsIter;
|
||||
@@ -817,6 +820,7 @@ public:
|
||||
void MoveBottom(bool aSelect = false);
|
||||
void MoveHome(bool aSelect = false);
|
||||
void MoveEnd(bool aSelect = false);
|
||||
void MoveToMatchedBracket(bool aSelect = false);
|
||||
|
||||
void SetSelectionStart(const Coordinates& aPosition);
|
||||
void SetSelectionEnd(const Coordinates& aPosition);
|
||||
@@ -961,6 +965,25 @@ private:
|
||||
|
||||
typedef std::vector<UndoRecord> UndoBuffer;
|
||||
|
||||
struct MatchedBracket {
|
||||
bool mActive=false;
|
||||
bool mChanged=false;
|
||||
Coordinates mNearCursor = {};
|
||||
Coordinates mMatched = {};
|
||||
static const std::string mSeparators;
|
||||
static const std::string mOperators;
|
||||
MatchedBracket(const MatchedBracket &other) : mActive(other.mActive), mChanged(other.mChanged), mNearCursor(other.mNearCursor), mMatched(other.mMatched) {}
|
||||
MatchedBracket() : mActive(false), mChanged(false), mNearCursor(0,0), mMatched(0,0) {}
|
||||
MatchedBracket(bool active, bool changed, const Coordinates &nearCursor, const Coordinates &matched) : mActive(active), mChanged(changed), mNearCursor(nearCursor), mMatched(matched) {}
|
||||
bool CheckPosition(TextEditor *editor, const Coordinates &aFrom);
|
||||
bool IsNearABracket(TextEditor *editor, const Coordinates &aFrom);
|
||||
int DetectDirection(TextEditor *editor, const Coordinates &aFrom);
|
||||
|
||||
void FindMatchingBracket(TextEditor *editor);
|
||||
bool IsActive() const { return mActive; }
|
||||
bool hasChanged() const { return mChanged; }
|
||||
};
|
||||
|
||||
void ProcessInputs();
|
||||
void ColorizeRange();
|
||||
void ColorizeInternal();
|
||||
@@ -980,11 +1003,11 @@ private:
|
||||
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;
|
||||
Coordinates GetCharacterCoordinates(int aLine, int aIndex) const;
|
||||
int GetLineCharacterCount(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 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;
|
||||
@@ -1038,6 +1061,7 @@ private:
|
||||
bool mIgnoreImGuiChild = false;
|
||||
bool mShowWhitespaces = true;
|
||||
|
||||
MatchedBracket mMatchedBracket={};
|
||||
Palette mPalette = {};
|
||||
LanguageDefinition mLanguageDefinition = {};
|
||||
RegexList mRegexList;
|
||||
|
||||
@@ -29,6 +29,9 @@ const int TextEditor::sCursorBlinkOnTime = 800;
|
||||
TextEditor::Palette sPaletteBase = TextEditor::GetDarkPalette();
|
||||
|
||||
TextEditor::FindReplaceHandler::FindReplaceHandler() : mWholeWord(false),mFindRegEx(false),mMatchCase(false) {}
|
||||
const std::string TextEditor::MatchedBracket::mSeparators = "()[]{}";
|
||||
const std::string TextEditor::MatchedBracket::mOperators = "<>";
|
||||
|
||||
|
||||
TextEditor::TextEditor() {
|
||||
mStartTime = ImGui::GetTime() * 1000;
|
||||
@@ -131,13 +134,16 @@ TextEditor::Coordinates TextEditor::GetActualCursorCoordinates() const {
|
||||
|
||||
TextEditor::Coordinates TextEditor::SanitizeCoordinates(const Coordinates &aValue) const {
|
||||
Coordinates result = aValue;
|
||||
if (aValue.mLine < 0)
|
||||
result.mLine = mLines.size() + aValue.mLine;
|
||||
if (aValue.mColumn < 0)
|
||||
result.mColumn = GetLineMaxColumn(result.mLine) + aValue.mColumn + 1;
|
||||
auto lineCount = (int)mLines.size();
|
||||
if (aValue.mLine < 0 && lineCount + aValue.mLine >= 0)
|
||||
result.mLine = lineCount + aValue.mLine;
|
||||
|
||||
result.mLine = std::clamp(result.mLine, 0, (int)mLines.size()-1);
|
||||
result.mColumn = std::clamp(result.mColumn, 0, GetLineMaxColumn(result.mLine));
|
||||
auto maxColumn = GetLineMaxColumn(result.mLine) + 1;
|
||||
if (aValue.mColumn < 0 && maxColumn + aValue.mColumn >= 0)
|
||||
result.mColumn = maxColumn + aValue.mColumn;
|
||||
|
||||
result.mLine = std::clamp(result.mLine, 0, lineCount - 1);
|
||||
result.mColumn = std::clamp(result.mColumn, 0, maxColumn - 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -196,7 +202,7 @@ void TextEditor::Advance(Coordinates &aCoordinates) const {
|
||||
auto characterIndex = GetCharacterIndex(aCoordinates);
|
||||
int maxDelta = line.size() - characterIndex;
|
||||
characterIndex += std::min(UTF8CharLength(line[characterIndex]), maxDelta);
|
||||
aCoordinates.mColumn = GetCharacterColumn(aCoordinates.mLine, characterIndex);
|
||||
aCoordinates.mColumn = line.GetCharacterColumn(characterIndex);
|
||||
}
|
||||
|
||||
void TextEditor::DeleteRange(const Coordinates &aStart, const Coordinates &aEnd) {
|
||||
@@ -338,7 +344,7 @@ TextEditor::Coordinates TextEditor::FindWordStart(const Coordinates &aFrom) cons
|
||||
while (cindex > 0 && isspace(line.mChars[cindex-1]))
|
||||
--cindex;
|
||||
}
|
||||
return Coordinates(at.mLine, GetCharacterColumn(at.mLine, cindex));
|
||||
return GetCharacterCoordinates(at.mLine, cindex);
|
||||
}
|
||||
|
||||
TextEditor::Coordinates TextEditor::FindWordEnd(const Coordinates &aFrom) const {
|
||||
@@ -359,7 +365,7 @@ TextEditor::Coordinates TextEditor::FindWordEnd(const Coordinates &aFrom) const
|
||||
while (cindex < (int)line.mChars.size() && isspace(line.mChars[cindex]))
|
||||
++cindex;
|
||||
}
|
||||
return Coordinates(aFrom.mLine, GetCharacterColumn(aFrom.mLine, cindex));
|
||||
return GetCharacterCoordinates(at.mLine, cindex);
|
||||
}
|
||||
|
||||
TextEditor::Coordinates TextEditor::FindNextWord(const Coordinates &aFrom) const {
|
||||
@@ -381,7 +387,7 @@ TextEditor::Coordinates TextEditor::FindNextWord(const Coordinates &aFrom) const
|
||||
while (cindex < (int)line.mChars.size() && (ispunct(line.mChars[cindex])))
|
||||
++cindex;
|
||||
}
|
||||
return Coordinates(aFrom.mLine, GetCharacterColumn(aFrom.mLine, cindex));
|
||||
return GetCharacterCoordinates(at.mLine, cindex);
|
||||
}
|
||||
|
||||
TextEditor::Coordinates TextEditor::FindPreviousWord(const Coordinates &aFrom) const {
|
||||
@@ -403,7 +409,7 @@ TextEditor::Coordinates TextEditor::FindPreviousWord(const Coordinates &aFrom) c
|
||||
while (cindex > 0 && ispunct(line.mChars[cindex-1]))
|
||||
--cindex;
|
||||
}
|
||||
return Coordinates(at.mLine, GetCharacterColumn(at.mLine, cindex));
|
||||
return GetCharacterCoordinates(at.mLine, cindex);
|
||||
}
|
||||
|
||||
|
||||
@@ -469,25 +475,24 @@ int TextEditor::GetCharacterIndex(const Coordinates &aCoordinates) const {
|
||||
return index;
|
||||
}
|
||||
|
||||
int TextEditor::GetCharacterColumn(int aLine, int aIndex) const {
|
||||
if (aLine >= mLines.size())
|
||||
return 0;
|
||||
if (aLine < 0)
|
||||
return 0;
|
||||
auto &line = mLines[aLine];
|
||||
int TextEditor::Line::GetCharacterColumn(int aIndex) const {
|
||||
int col = 0;
|
||||
int i = 0;
|
||||
while (i < aIndex && i < (int)line.size()) {
|
||||
auto c = line[i];
|
||||
while (i < aIndex && i < (int)size()) {
|
||||
auto c = mChars[i];
|
||||
i += UTF8CharLength(c);
|
||||
if (c == '\t')
|
||||
col = (col / mTabSize) * mTabSize + mTabSize;
|
||||
else
|
||||
col++;
|
||||
col++;
|
||||
}
|
||||
return col;
|
||||
}
|
||||
|
||||
TextEditor::Coordinates TextEditor::GetCharacterCoordinates(int aLine, int aIndex) const {
|
||||
if (aLine < 0 || aLine >= (int)mLines.size())
|
||||
return Coordinates(0, 0);
|
||||
auto &line = mLines[aLine];
|
||||
return Coordinates(aLine, line.GetCharacterColumn(aIndex));
|
||||
}
|
||||
|
||||
int TextEditor::GetStringCharacterCount(std::string str) const {
|
||||
if (str.empty())
|
||||
return 0;
|
||||
@@ -843,6 +848,198 @@ void TextEditor::SetFocus() {
|
||||
mUpdateFocus = false;
|
||||
}
|
||||
|
||||
bool TextEditor::MatchedBracket::CheckPosition(TextEditor *editor, const Coordinates &aFrom) {
|
||||
auto lineIndex = aFrom.mLine;
|
||||
auto line = editor->mLines[lineIndex].mChars;
|
||||
auto colors = editor->mLines[lineIndex].mColors;
|
||||
if (!line.empty() && colors.empty())
|
||||
return false;
|
||||
auto result = aFrom.mColumn;
|
||||
auto character = line[result];
|
||||
auto color = colors[result];
|
||||
if (mSeparators.find(character) != std::string::npos && (static_cast<PaletteIndex>(color) == PaletteIndex::Separator || static_cast<PaletteIndex>(color) == PaletteIndex::WarningText) ||
|
||||
mOperators.find(character) != std::string::npos && (static_cast<PaletteIndex>(color) == PaletteIndex::Operator || static_cast<PaletteIndex>(color) == PaletteIndex::WarningText)) {
|
||||
if (mNearCursor != editor->GetCharacterCoordinates(lineIndex, result)) {
|
||||
mNearCursor = editor->GetCharacterCoordinates(lineIndex, result);
|
||||
mChanged = true;
|
||||
}
|
||||
mActive = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int TextEditor::MatchedBracket::DetectDirection(TextEditor *editor, const Coordinates &aFrom) {
|
||||
int result = 0; // -1 previous 0 current
|
||||
auto from = editor->SanitizeCoordinates(aFrom);
|
||||
auto lineIndex = from.mLine;
|
||||
auto charIndex = editor->GetCharacterIndex(from);
|
||||
if (charIndex == 0) // no previous character
|
||||
return 0;
|
||||
auto line = editor->mLines[lineIndex].mChars;
|
||||
auto ch1 = line[charIndex-1];
|
||||
auto ch2 = line[charIndex];
|
||||
std::string brackets = "()[]{}<>";
|
||||
auto idx1 = brackets.find(ch1);
|
||||
auto idx2 = brackets.find(ch2);
|
||||
if (idx1 == std::string::npos && idx2 == std::string::npos) // no brackets
|
||||
return 0;
|
||||
if (idx1 != std::string::npos && idx2 != std::string::npos) {
|
||||
if (idx1 % 2) // closing bracket + any bracket
|
||||
return -1;
|
||||
else if (!(idx1 % 2) && !(idx2 % 2)) // opening bracket + opening bracket
|
||||
return 0;
|
||||
} else if (idx1 != std::string::npos) // only first bracket
|
||||
return -1;
|
||||
else if (idx2 != std::string::npos) // only second bracket
|
||||
return 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool TextEditor::MatchedBracket::IsNearABracket(TextEditor *editor, const Coordinates &aFrom) {
|
||||
auto from = editor->SanitizeCoordinates(aFrom);
|
||||
auto lineIndex = from.mLine;
|
||||
auto charIndex = editor->GetCharacterIndex(from);
|
||||
auto direction1 = DetectDirection(editor, from);
|
||||
auto direction2 = -(direction1 + 1);
|
||||
if (CheckPosition(editor, Coordinates(lineIndex, charIndex+direction1)))
|
||||
return true;
|
||||
if (CheckPosition(editor, Coordinates(lineIndex, charIndex+direction2)))
|
||||
return true;
|
||||
uint64_t result = 0;
|
||||
std::string line = editor->mLines[lineIndex].mChars;
|
||||
if (charIndex==0)
|
||||
if (line[0] == ' ')
|
||||
result = std::string::npos;
|
||||
else
|
||||
result = 0;
|
||||
else
|
||||
result = line.find_last_not_of(' ', charIndex-1);
|
||||
if (result != std::string::npos) {
|
||||
if (CheckPosition(editor, Coordinates(lineIndex, result)))
|
||||
return true;
|
||||
}
|
||||
result = line.find_first_not_of(' ', charIndex);
|
||||
if (result != std::string::npos) {
|
||||
if (CheckPosition(editor, Coordinates(lineIndex, result)))
|
||||
return true;
|
||||
}
|
||||
if (mActive) {
|
||||
editor->mLines[mNearCursor.mLine].mColorized = false;
|
||||
editor->mLines[mMatched.mLine].mColorized = false;
|
||||
mActive = false;
|
||||
editor->Colorize();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void TextEditor::MatchedBracket::FindMatchingBracket(TextEditor *editor) {
|
||||
auto from = editor->SanitizeCoordinates(mNearCursor);
|
||||
mMatched = from;
|
||||
auto lineIndex = from.mLine;
|
||||
auto maxLineIndex = editor->mLines.size() - 1;
|
||||
auto charIndex = editor->GetCharacterIndex(from);
|
||||
std::string line = editor->mLines[lineIndex].mChars;
|
||||
std::string colors = editor->mLines[lineIndex].mColors;
|
||||
if (!line.empty() && colors.empty()) {
|
||||
mActive = false;
|
||||
return;
|
||||
}
|
||||
std::string brackets = "()[]{}<>";
|
||||
char bracketChar = line[charIndex];
|
||||
char color1;
|
||||
auto idx = brackets.find_first_of(bracketChar);
|
||||
if (idx == std::string::npos) {
|
||||
if (mActive) {
|
||||
mActive = false;
|
||||
editor->Colorize();
|
||||
}
|
||||
return;
|
||||
}
|
||||
auto bracketChar2 = brackets[idx ^ 1];
|
||||
brackets = bracketChar;
|
||||
brackets += bracketChar2;
|
||||
int32_t direction = 1 - 2 * (idx % 2);
|
||||
if (idx > 5)
|
||||
color1 = static_cast<char>(PaletteIndex::Operator);
|
||||
else
|
||||
color1 = static_cast<char>(PaletteIndex::Separator);
|
||||
char color = static_cast<char>(PaletteIndex::WarningText);
|
||||
int32_t depth = 1;
|
||||
if (charIndex == (line.size()-1) * (1 + direction) / 2 ) {
|
||||
if (lineIndex == maxLineIndex * (1 + direction) / 2) {
|
||||
mActive = false;
|
||||
return;
|
||||
}
|
||||
lineIndex += direction;
|
||||
line = editor->mLines[lineIndex].mChars;
|
||||
colors = editor->mLines[lineIndex].mColors;
|
||||
if (!line.empty() && colors.empty()) {
|
||||
mActive = false;
|
||||
return;
|
||||
}
|
||||
charIndex = (line.size()-1) * (1 - direction) / 2 - direction;
|
||||
}
|
||||
for (int32_t i = charIndex + direction; ; i += direction) {
|
||||
if (direction == 1)
|
||||
idx = line.find_first_of(brackets, i);
|
||||
else
|
||||
idx = line.find_last_of(brackets, i);
|
||||
if (idx != std::string::npos) {
|
||||
if (line[idx] == bracketChar && (colors[idx] == color || colors[idx] == color1)) {
|
||||
++depth;
|
||||
i = idx;
|
||||
} else if (line[idx] == bracketChar2 && (colors[idx] == color) || colors[idx] == color1) {
|
||||
--depth;
|
||||
if (depth == 0) {
|
||||
if (mMatched != editor->GetCharacterCoordinates(lineIndex, idx)) {
|
||||
mMatched = editor->GetCharacterCoordinates(lineIndex, idx);
|
||||
mChanged = true;
|
||||
}
|
||||
mActive = true;
|
||||
break;
|
||||
}
|
||||
i = idx;
|
||||
} else {
|
||||
i = idx;
|
||||
}
|
||||
} else {
|
||||
if (direction == 1)
|
||||
i = line.size()-1;
|
||||
else
|
||||
i = 0;
|
||||
}
|
||||
if ((int32_t)(direction * i) >= (int32_t)((line.size() - 1) * (1 + direction) / 2)) {
|
||||
if (lineIndex == maxLineIndex * (1 + direction) / 2) {
|
||||
if (mActive) {
|
||||
mActive = false;
|
||||
mChanged = true;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
lineIndex += direction;
|
||||
line = editor->mLines[lineIndex].mChars;
|
||||
colors = editor->mLines[lineIndex].mColors;
|
||||
if (!line.empty() && colors.empty()) {
|
||||
mActive = false;
|
||||
return;
|
||||
}
|
||||
i = (line.size() - 1) * (1 - direction) / 2 - direction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mChanged) {
|
||||
editor->mLines[mNearCursor.mLine].mColorized = false;
|
||||
editor->mLines[mMatched.mLine].mColorized = false;
|
||||
|
||||
editor->Colorize();
|
||||
mChanged = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TextEditor::RenderText(const char *aTitle, const ImVec2 &lineNumbersStartPos, const ImVec2 &textEditorSize) {
|
||||
/* Compute mCharAdvance regarding scaled font size (Ctrl + mouse wheel)*/
|
||||
const float fontSize = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, "#", nullptr, nullptr).x;
|
||||
@@ -1001,6 +1198,8 @@ void TextEditor::RenderText(const char *aTitle, const ImVec2 &lineNumbersStartPo
|
||||
drawList->AddRectFilled(cstart, cend, mPalette[(int)PaletteIndex::Cursor]);
|
||||
if (elapsed > sCursorBlinkInterval)
|
||||
mStartTime = timeEnd;
|
||||
if (mMatchedBracket.IsNearABracket(this, mState.mCursorPosition))
|
||||
mMatchedBracket.FindMatchingBracket(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1349,7 +1548,7 @@ void TextEditor::EnterCharacter(ImWchar aChar, bool aShift) {
|
||||
}
|
||||
|
||||
if (modified) {
|
||||
start = Coordinates(start.mLine, GetCharacterColumn(start.mLine, 0));
|
||||
start = GetCharacterCoordinates(start.mLine, 0);
|
||||
Coordinates rangeEnd;
|
||||
if (originalEnd.mColumn != 0) {
|
||||
end = Coordinates(end.mLine, GetLineMaxColumn(end.mLine));
|
||||
@@ -1414,7 +1613,7 @@ void TextEditor::EnterCharacter(ImWchar aChar, bool aShift) {
|
||||
newLine.insert(newLine.end(), line.begin() + cstart, line.end());
|
||||
line.erase(line.begin() + cstart,-1);
|
||||
line.mColorized = false;
|
||||
SetCursorPosition(Coordinates(coord.mLine + 1, GetCharacterColumn(coord.mLine + 1, cpos)));
|
||||
SetCursorPosition(GetCharacterCoordinates(coord.mLine + 1, cpos));
|
||||
u.mAdded = (char)aChar;
|
||||
} else if (aChar == '\t') {
|
||||
auto &line = mLines[coord.mLine];
|
||||
@@ -1425,7 +1624,7 @@ void TextEditor::EnterCharacter(ImWchar aChar, bool aShift) {
|
||||
std::string spaces(spacesToInsert, ' ');
|
||||
line.insert(line.begin() + cindex, spaces.begin(), spaces.end());
|
||||
line.mColorized = false;
|
||||
SetCursorPosition(Coordinates(coord.mLine, GetCharacterColumn(coord.mLine, cindex + spacesToInsert)));
|
||||
SetCursorPosition(GetCharacterCoordinates(coord.mLine, cindex + spacesToInsert));
|
||||
} else {
|
||||
auto spacesToRemove = (cindex % mTabSize);
|
||||
if (spacesToRemove == 0) spacesToRemove = mTabSize;
|
||||
@@ -1437,7 +1636,7 @@ void TextEditor::EnterCharacter(ImWchar aChar, bool aShift) {
|
||||
}
|
||||
}
|
||||
line.mColorized = false;
|
||||
SetCursorPosition(Coordinates(coord.mLine, GetCharacterColumn(coord.mLine, std::max(0, cindex))));
|
||||
SetCursorPosition(GetCharacterCoordinates(coord.mLine, std::max(0, cindex)));
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -1451,7 +1650,7 @@ void TextEditor::EnterCharacter(ImWchar aChar, bool aShift) {
|
||||
auto d = UTF8CharLength(line[cindex]);
|
||||
|
||||
u.mRemovedStart = mState.mCursorPosition;
|
||||
u.mRemovedEnd = Coordinates(coord.mLine, GetCharacterColumn(coord.mLine, cindex + d));
|
||||
u.mRemovedEnd = GetCharacterCoordinates(coord.mLine, cindex + d);
|
||||
u.mRemoved = std::string(line.mChars.begin() + cindex, line.mChars.begin() + cindex + d);
|
||||
line.erase(line.begin() + cindex, d);
|
||||
line.mColorized = false;
|
||||
@@ -1460,7 +1659,7 @@ void TextEditor::EnterCharacter(ImWchar aChar, bool aShift) {
|
||||
line.mColorized = false;
|
||||
u.mAdded = buf;
|
||||
auto charCount = GetStringCharacterCount(buf);
|
||||
SetCursorPosition(Coordinates(coord.mLine, GetCharacterColumn(coord.mLine, cindex + charCount)));
|
||||
SetCursorPosition(GetCharacterCoordinates(coord.mLine, cindex + charCount));
|
||||
} else
|
||||
return;
|
||||
}
|
||||
@@ -1593,6 +1792,32 @@ void TextEditor::JumpToCoords(const Coordinates &aNewPos) {
|
||||
SetFocusAtCoords(aNewPos);
|
||||
}
|
||||
|
||||
void TextEditor::MoveToMatchedBracket(bool aSelect) {
|
||||
ResetCursorBlinkTime();
|
||||
if (mMatchedBracket.IsNearABracket(this, mState.mCursorPosition)) {
|
||||
mMatchedBracket.FindMatchingBracket(this);
|
||||
auto oldPos = mMatchedBracket.mNearCursor;
|
||||
auto newPos = mMatchedBracket.mMatched;
|
||||
if (newPos != Coordinates(-1, -1)) {
|
||||
if (aSelect) {
|
||||
if (oldPos == mInteractiveStart)
|
||||
mInteractiveStart = newPos;
|
||||
else if (oldPos == mInteractiveEnd)
|
||||
mInteractiveEnd = newPos;
|
||||
else {
|
||||
mInteractiveStart = newPos;
|
||||
mInteractiveEnd = oldPos;
|
||||
}
|
||||
} else
|
||||
mInteractiveStart = mInteractiveEnd = newPos;
|
||||
|
||||
SetSelection(mInteractiveStart, mInteractiveEnd);
|
||||
SetCursorPosition(newPos);
|
||||
EnsureCursorVisible();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TextEditor::MoveUp(int aAmount, bool aSelect) {
|
||||
ResetCursorBlinkTime();
|
||||
auto oldPos = mState.mCursorPosition;
|
||||
@@ -1696,7 +1921,7 @@ void TextEditor::MoveLeft(int aAmount, bool aSelect, bool aWordMode) {
|
||||
}
|
||||
}
|
||||
|
||||
mState.mCursorPosition = Coordinates(lindex, GetCharacterColumn(lindex, cindex));
|
||||
mState.mCursorPosition = GetCharacterCoordinates(lindex, cindex);
|
||||
|
||||
IM_ASSERT(mState.mCursorPosition.mColumn >= 0);
|
||||
if (aSelect) {
|
||||
@@ -1728,7 +1953,7 @@ void TextEditor::MoveRight(int aAmount, bool aSelect, bool aWordMode) {
|
||||
auto lindex = mState.mCursorPosition.mLine;
|
||||
|
||||
while (aAmount-- > 0) {
|
||||
auto &line = mLines[lindex];
|
||||
const auto &line = mLines[lindex];
|
||||
|
||||
if (cindex >= line.size()) {
|
||||
if (lindex < mLines.size() - 1) {
|
||||
@@ -1749,7 +1974,7 @@ void TextEditor::MoveRight(int aAmount, bool aSelect, bool aWordMode) {
|
||||
}
|
||||
}
|
||||
|
||||
mState.mCursorPosition = Coordinates(lindex, GetCharacterColumn(lindex, cindex));
|
||||
mState.mCursorPosition = GetCharacterCoordinates(lindex, cindex);
|
||||
|
||||
IM_ASSERT(mState.mCursorPosition.mColumn >= 0);
|
||||
if (aSelect) {
|
||||
@@ -1989,7 +2214,7 @@ void TextEditor::Backspace() {
|
||||
|
||||
u.mRemovedStart = u.mRemovedEnd = GetActualCursorCoordinates();
|
||||
--u.mRemovedStart.mColumn;
|
||||
mState.mCursorPosition.mColumn = GetCharacterColumn(mState.mCursorPosition.mLine, cindex);
|
||||
mState.mCursorPosition.mColumn = line.GetCharacterColumn(cindex);
|
||||
u.mRemoved = GetText(u.mRemovedStart, u.mRemovedEnd);
|
||||
if (cend > cindex && cend < (int) line.size())
|
||||
line.erase(line.begin() + cindex, cend-cindex);
|
||||
@@ -2019,10 +2244,7 @@ void TextEditor::SelectWordUnderCursor() {
|
||||
}
|
||||
|
||||
void TextEditor::SelectAll() {
|
||||
if (isEmpty())
|
||||
return;
|
||||
|
||||
SetSelection(Coordinates(0, 0), Coordinates((int)mLines.size(), mLines.empty() ? 0 : GetLineMaxColumn((int)mLines.size() - 1)));
|
||||
SetSelection(Coordinates(0, 0), Coordinates(-1, -1));
|
||||
}
|
||||
|
||||
bool TextEditor::HasSelection() const {
|
||||
@@ -2096,7 +2318,7 @@ std::string TextEditor::ReplaceStrings(std::string string, const std::string &se
|
||||
}
|
||||
|
||||
std::vector<std::string> TextEditor::SplitString(const std::string &string, const std::string &delimiter, bool removeEmpty) {
|
||||
if (delimiter.empty()) {
|
||||
if (delimiter.empty() || string.empty()) {
|
||||
return { string };
|
||||
}
|
||||
|
||||
@@ -2113,7 +2335,8 @@ std::vector<std::string> TextEditor::SplitString(const std::string &string, cons
|
||||
result.emplace_back(std::move(token));
|
||||
}
|
||||
|
||||
result.emplace_back(string.substr(start));
|
||||
if (start < string.length())
|
||||
result.emplace_back(string.substr(start));
|
||||
|
||||
if (removeEmpty)
|
||||
std::erase_if(result, [](const auto &string) { return string.empty(); });
|
||||
@@ -2757,7 +2980,14 @@ void TextEditor::ColorizeRange() {
|
||||
token_length = token_end - token_begin;
|
||||
}
|
||||
}
|
||||
if ((token_color != PaletteIndex::Directive && token_color != PaletteIndex::PreprocIdentifier) || flags.mBits.mDeactivated) {
|
||||
if (flags.mBits.mMatchedBracket) {
|
||||
if (token_color != PaletteIndex::WarningText) {
|
||||
token_color = PaletteIndex::WarningText;
|
||||
}
|
||||
token_length = token_end - token_begin;
|
||||
} else if (flags.mBits.mPreprocessor && !flags.mBits.mDeactivated) {
|
||||
token_length = token_end - token_begin;
|
||||
} else if ((token_color != PaletteIndex::Directive && token_color != PaletteIndex::PreprocIdentifier) || flags.mBits.mDeactivated) {
|
||||
if (flags.mBits.mDeactivated && flags.mBits.mPreprocessor) {
|
||||
token_color = PaletteIndex::PreprocessorDeactivated;
|
||||
token_begin -= 1;
|
||||
@@ -2769,9 +2999,9 @@ void TextEditor::ColorizeRange() {
|
||||
}
|
||||
|
||||
auto flag = line.mFlags[token_offset];
|
||||
token_length = line.mFlags.find_first_not_of(flag, token_offset + 1);
|
||||
if (token_length == std::string::npos)
|
||||
token_length = line.size() - token_offset;
|
||||
token_length = line.mFlags.find_first_not_of(flag, token_offset + 1);
|
||||
if (token_length == std::string::npos)
|
||||
token_length = line.size() - token_offset;
|
||||
else
|
||||
token_length -= token_offset;
|
||||
|
||||
@@ -2816,6 +3046,8 @@ void TextEditor::ColorizeInternal() {
|
||||
auto withinNotDef = false;
|
||||
auto currentLine = 0;
|
||||
auto commentLength = 0;
|
||||
auto matchedBracket = false;
|
||||
std::string brackets = "()[]{}<>";
|
||||
|
||||
std::vector<bool> ifDefs;
|
||||
ifDefs.push_back(true);
|
||||
@@ -2828,170 +3060,184 @@ void TextEditor::ColorizeInternal() {
|
||||
line.mFlags.resize(lineLength, 0);
|
||||
line.mColorized = false;
|
||||
}
|
||||
//if (!line.mColorized) {
|
||||
|
||||
auto withinComment = false;
|
||||
auto withinDocComment = false;
|
||||
auto withinPreproc = false;
|
||||
auto firstChar = true; // there is no other non-whitespace characters in the line before
|
||||
|
||||
auto setGlyphFlags = [&](int index) {
|
||||
Line::Flags flags(0);
|
||||
flags.mBits.mComment = withinComment;
|
||||
flags.mBits.mBlockComment = withinBlockComment;
|
||||
flags.mBits.mDocComment = withinDocComment;
|
||||
flags.mBits.mGlobalDocComment = withinGlobalDocComment;
|
||||
flags.mBits.mBlockDocComment = withinBlockDocComment;
|
||||
flags.mBits.mDeactivated = withinNotDef;
|
||||
if (mLines[currentLine].mFlags[index] != flags.mValue) {
|
||||
mLines[currentLine].mColorized = false;
|
||||
mLines[currentLine].mFlags[index] = flags.mValue;
|
||||
auto withinComment = false;
|
||||
auto withinDocComment = false;
|
||||
auto withinPreproc = false;
|
||||
auto firstChar = true; // there is no other non-whitespace characters in the line before
|
||||
|
||||
auto setGlyphFlags = [&](int index) {
|
||||
Line::Flags flags(0);
|
||||
flags.mBits.mComment = withinComment;
|
||||
flags.mBits.mBlockComment = withinBlockComment;
|
||||
flags.mBits.mDocComment = withinDocComment;
|
||||
flags.mBits.mGlobalDocComment = withinGlobalDocComment;
|
||||
flags.mBits.mBlockDocComment = withinBlockDocComment;
|
||||
flags.mBits.mDeactivated = withinNotDef;
|
||||
flags.mBits.mMatchedBracket = matchedBracket;
|
||||
if (mLines[currentLine].mFlags[index] != flags.mValue) {
|
||||
mLines[currentLine].mColorized = false;
|
||||
mLines[currentLine].mFlags[index] = flags.mValue;
|
||||
}
|
||||
};
|
||||
|
||||
auto currentIndex = 0;
|
||||
if (line.empty())
|
||||
continue;
|
||||
while (currentIndex < lineLength) {
|
||||
|
||||
auto &g = line[currentIndex];
|
||||
auto c = g;
|
||||
|
||||
matchedBracket = false;
|
||||
if (MatchedBracket::mSeparators.contains(c) && mMatchedBracket.IsActive()) {
|
||||
if (mMatchedBracket.mNearCursor == Coordinates(currentLine, currentIndex) || mMatchedBracket.mMatched == Coordinates(currentLine, currentIndex))
|
||||
matchedBracket = true;
|
||||
} else if (MatchedBracket::mOperators.contains(c) && mMatchedBracket.IsActive()) {
|
||||
if (mMatchedBracket.mNearCursor == Coordinates(currentLine, currentIndex) || mMatchedBracket.mMatched == Coordinates(currentLine, currentIndex)) {
|
||||
if ((c == '<' && line.mColors[currentIndex - 1] == static_cast<char>(PaletteIndex::UserDefinedType)) ||
|
||||
(c == '>' && (mMatchedBracket.mMatched.mColumn > 0 && line.mColors[mMatchedBracket.mMatched.mColumn - 1] == static_cast<char>(PaletteIndex::UserDefinedType)) ||
|
||||
(mMatchedBracket.mNearCursor.mColumn > 0 && line.mColors[mMatchedBracket.mNearCursor.mColumn - 1] == static_cast<char>(PaletteIndex::UserDefinedType)))) {
|
||||
matchedBracket = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
auto currentIndex = 0;
|
||||
if (line.empty())
|
||||
continue;
|
||||
while (currentIndex < lineLength) {
|
||||
|
||||
auto &g = line[currentIndex];
|
||||
auto c = g;
|
||||
if (c != mLanguageDefinition.mPreprocChar && !isspace(c))
|
||||
firstChar = false;
|
||||
|
||||
if (c != mLanguageDefinition.mPreprocChar && !isspace(c))
|
||||
firstChar = false;
|
||||
bool inComment = (commentStartLine < currentLine || (commentStartLine == currentLine && commentStartIndex <= currentIndex));
|
||||
|
||||
bool inComment = (commentStartLine < currentLine || (commentStartLine == currentLine && commentStartIndex <= currentIndex));
|
||||
|
||||
if (withinString) {
|
||||
if (withinString) {
|
||||
setGlyphFlags(currentIndex);
|
||||
if (c == '\\') {
|
||||
currentIndex++;
|
||||
setGlyphFlags(currentIndex);
|
||||
if (c == '\\') {
|
||||
currentIndex++;
|
||||
setGlyphFlags(currentIndex);
|
||||
} else if (c == '\"')
|
||||
withinString = false;
|
||||
} else {
|
||||
if (firstChar && c == mLanguageDefinition.mPreprocChar && !inComment && !withinComment && !withinDocComment && !withinString) {
|
||||
withinPreproc = true;
|
||||
std::string directive;
|
||||
auto start = currentIndex + 1;
|
||||
while (start < (int) line.size() && !isspace(line[start])) {
|
||||
directive += line[start];
|
||||
start++;
|
||||
}
|
||||
|
||||
while (start < (int) line.size() && isspace(line[start]))
|
||||
start++;
|
||||
|
||||
if (directive == "endif" && !ifDefs.empty()) {
|
||||
ifDefs.pop_back();
|
||||
withinNotDef = !ifDefs.back();
|
||||
} else {
|
||||
std::string identifier;
|
||||
while (start < (int) line.size() && !isspace(line[start])) {
|
||||
identifier += line[start];
|
||||
start++;
|
||||
}
|
||||
if (directive == "define") {
|
||||
if (identifier.size() > 0 && !withinNotDef && std::find(mDefines.begin(), mDefines.end(), identifier) == mDefines.end())
|
||||
mDefines.push_back(identifier);
|
||||
} else if (directive == "undef") {
|
||||
if (identifier.size() > 0 && !withinNotDef)
|
||||
mDefines.erase(std::remove(mDefines.begin(), mDefines.end(), identifier), mDefines.end());
|
||||
} else if (directive == "ifdef") {
|
||||
if (!withinNotDef) {
|
||||
bool isConditionMet = std::find(mDefines.begin(), mDefines.end(), identifier) != mDefines.end();
|
||||
ifDefs.push_back(isConditionMet);
|
||||
} else
|
||||
ifDefs.push_back(false);
|
||||
} else if (directive == "ifndef") {
|
||||
if (!withinNotDef) {
|
||||
bool isConditionMet = std::find(mDefines.begin(), mDefines.end(), identifier) == mDefines.end();
|
||||
ifDefs.push_back(isConditionMet);
|
||||
} else
|
||||
ifDefs.push_back(false);
|
||||
}
|
||||
}
|
||||
} else if (c == '\"')
|
||||
withinString = false;
|
||||
} else {
|
||||
if (firstChar && c == mLanguageDefinition.mPreprocChar && !inComment && !withinComment && !withinDocComment && !withinString) {
|
||||
withinPreproc = true;
|
||||
std::string directive;
|
||||
auto start = currentIndex + 1;
|
||||
while (start < (int) line.size() && !isspace(line[start])) {
|
||||
directive += line[start];
|
||||
start++;
|
||||
}
|
||||
|
||||
if (c == '\"' && !withinPreproc && !inComment && !withinComment && !withinDocComment) {
|
||||
withinString = true;
|
||||
setGlyphFlags(currentIndex);
|
||||
while (start < (int) line.size() && isspace(line[start]))
|
||||
start++;
|
||||
|
||||
if (directive == "endif" && !ifDefs.empty()) {
|
||||
ifDefs.pop_back();
|
||||
withinNotDef = !ifDefs.back();
|
||||
} else {
|
||||
auto pred = [](const char &a, const char &b) { return a == b; };
|
||||
std::string identifier;
|
||||
while (start < (int) line.size() && !isspace(line[start])) {
|
||||
identifier += line[start];
|
||||
start++;
|
||||
}
|
||||
if (directive == "define") {
|
||||
if (identifier.size() > 0 && !withinNotDef && std::find(mDefines.begin(), mDefines.end(), identifier) == mDefines.end())
|
||||
mDefines.push_back(identifier);
|
||||
} else if (directive == "undef") {
|
||||
if (identifier.size() > 0 && !withinNotDef)
|
||||
mDefines.erase(std::remove(mDefines.begin(), mDefines.end(), identifier), mDefines.end());
|
||||
} else if (directive == "ifdef") {
|
||||
if (!withinNotDef) {
|
||||
bool isConditionMet = std::find(mDefines.begin(), mDefines.end(), identifier) != mDefines.end();
|
||||
ifDefs.push_back(isConditionMet);
|
||||
} else
|
||||
ifDefs.push_back(false);
|
||||
} else if (directive == "ifndef") {
|
||||
if (!withinNotDef) {
|
||||
bool isConditionMet = std::find(mDefines.begin(), mDefines.end(), identifier) == mDefines.end();
|
||||
ifDefs.push_back(isConditionMet);
|
||||
} else
|
||||
ifDefs.push_back(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto compareForth = [&](const std::string &a, const std::string &b) {
|
||||
return !a.empty() && (currentIndex + a.size() <= b.size()) && equals(a.begin(), a.end(), b.begin() + currentIndex, b.begin() + (currentIndex + a.size()), pred);
|
||||
};
|
||||
if (c == '\"' && !withinPreproc && !inComment && !withinComment && !withinDocComment) {
|
||||
withinString = true;
|
||||
setGlyphFlags(currentIndex);
|
||||
} else {
|
||||
auto pred = [](const char &a, const char &b) { return a == b; };
|
||||
|
||||
auto compareBack = [&](const std::string &a, const std::string &b) {
|
||||
return !a.empty() && currentIndex + 1 >= (int) a.size() && equals(a.begin(), a.end(), b.begin() + (currentIndex + 1 - a.size()), b.begin() + (currentIndex + 1), pred);
|
||||
};
|
||||
auto compareForth = [&](const std::string &a, const std::string &b) {
|
||||
return !a.empty() && (currentIndex + a.size() <= b.size()) && equals(a.begin(), a.end(), b.begin() + currentIndex, b.begin() + (currentIndex + a.size()), pred);
|
||||
};
|
||||
|
||||
if (!inComment && !withinComment && !withinDocComment && !withinPreproc && !withinString) {
|
||||
if (compareForth(mLanguageDefinition.mDocComment, line.mChars)) {
|
||||
withinDocComment = !inComment;
|
||||
commentLength = 3;
|
||||
} else if (compareForth(mLanguageDefinition.mSingleLineComment, line.mChars)) {
|
||||
withinComment = !inComment;
|
||||
commentLength = 2;
|
||||
} else {
|
||||
bool isGlobalDocComment = compareForth(mLanguageDefinition.mGlobalDocComment, line.mChars);
|
||||
bool isBlockDocComment = compareForth(mLanguageDefinition.mBlockDocComment, line.mChars);
|
||||
bool isBlockComment = compareForth(mLanguageDefinition.mCommentStart, line.mChars);
|
||||
if (isGlobalDocComment || isBlockDocComment || isBlockComment) {
|
||||
commentStartLine = currentLine;
|
||||
commentStartIndex = currentIndex;
|
||||
if (currentIndex < line.size() - 4 && isBlockComment &&
|
||||
line.mChars[currentIndex + 2] == '*' &&
|
||||
line.mChars[currentIndex + 3] == '/') {
|
||||
withinBlockComment = true;
|
||||
commentLength = 2;
|
||||
} else if (isGlobalDocComment) {
|
||||
withinGlobalDocComment = true;
|
||||
commentLength = 3;
|
||||
} else if (isBlockDocComment) {
|
||||
withinBlockDocComment = true;
|
||||
commentLength = 3;
|
||||
} else {
|
||||
withinBlockComment = true;
|
||||
commentLength = 2;
|
||||
}
|
||||
auto compareBack = [&](const std::string &a, const std::string &b) {
|
||||
return !a.empty() && currentIndex + 1 >= (int) a.size() && equals(a.begin(), a.end(), b.begin() + (currentIndex + 1 - a.size()), b.begin() + (currentIndex + 1), pred);
|
||||
};
|
||||
|
||||
if (!inComment && !withinComment && !withinDocComment && !withinPreproc && !withinString) {
|
||||
if (compareForth(mLanguageDefinition.mDocComment, line.mChars)) {
|
||||
withinDocComment = !inComment;
|
||||
commentLength = 3;
|
||||
} else if (compareForth(mLanguageDefinition.mSingleLineComment, line.mChars)) {
|
||||
withinComment = !inComment;
|
||||
commentLength = 2;
|
||||
} else {
|
||||
bool isGlobalDocComment = compareForth(mLanguageDefinition.mGlobalDocComment, line.mChars);
|
||||
bool isBlockDocComment = compareForth(mLanguageDefinition.mBlockDocComment, line.mChars);
|
||||
bool isBlockComment = compareForth(mLanguageDefinition.mCommentStart, line.mChars);
|
||||
if (isGlobalDocComment || isBlockDocComment || isBlockComment) {
|
||||
commentStartLine = currentLine;
|
||||
commentStartIndex = currentIndex;
|
||||
if (currentIndex < line.size() - 4 && isBlockComment &&
|
||||
line.mChars[currentIndex + 2] == '*' &&
|
||||
line.mChars[currentIndex + 3] == '/') {
|
||||
withinBlockComment = true;
|
||||
commentLength = 2;
|
||||
} else if (isGlobalDocComment) {
|
||||
withinGlobalDocComment = true;
|
||||
commentLength = 3;
|
||||
} else if (isBlockDocComment) {
|
||||
withinBlockDocComment = true;
|
||||
commentLength = 3;
|
||||
} else {
|
||||
withinBlockComment = true;
|
||||
commentLength = 2;
|
||||
}
|
||||
}
|
||||
inComment = (commentStartLine < currentLine || (commentStartLine == currentLine && commentStartIndex <= currentIndex));
|
||||
}
|
||||
setGlyphFlags(currentIndex);
|
||||
inComment = (commentStartLine < currentLine || (commentStartLine == currentLine && commentStartIndex <= currentIndex));
|
||||
}
|
||||
setGlyphFlags(currentIndex);
|
||||
|
||||
if (compareBack(mLanguageDefinition.mCommentEnd, line.mChars) && ((commentStartLine != currentLine) || (commentStartIndex + commentLength < currentIndex))) {
|
||||
withinBlockComment = false;
|
||||
withinBlockDocComment = false;
|
||||
withinGlobalDocComment = false;
|
||||
commentStartLine = endLine;
|
||||
commentStartIndex = 0;
|
||||
commentLength = 0;
|
||||
}
|
||||
if (compareBack(mLanguageDefinition.mCommentEnd, line.mChars) && ((commentStartLine != currentLine) || (commentStartIndex + commentLength < currentIndex))) {
|
||||
withinBlockComment = false;
|
||||
withinBlockDocComment = false;
|
||||
withinGlobalDocComment = false;
|
||||
commentStartLine = endLine;
|
||||
commentStartIndex = 0;
|
||||
commentLength = 0;
|
||||
}
|
||||
}
|
||||
if (currentIndex < line.size()) {
|
||||
Line::Flags flags(0);
|
||||
flags.mValue = mLines[currentLine].mFlags[currentIndex];
|
||||
flags.mBits.mPreprocessor = withinPreproc;
|
||||
}
|
||||
if (currentIndex < line.size()) {
|
||||
Line::Flags flags(0);
|
||||
flags.mValue = mLines[currentLine].mFlags[currentIndex];
|
||||
flags.mBits.mPreprocessor = withinPreproc;
|
||||
mLines[currentLine].mFlags[currentIndex] = flags.mValue;
|
||||
}
|
||||
auto utf8CharLength = UTF8CharLength(c);
|
||||
if (utf8CharLength > 1) {
|
||||
Line::Flags flags(0);
|
||||
flags.mValue = mLines[currentLine].mFlags[currentIndex];
|
||||
for (int j = 1; j < utf8CharLength; j++) {
|
||||
currentIndex++;
|
||||
mLines[currentLine].mFlags[currentIndex] = flags.mValue;
|
||||
}
|
||||
auto utf8CharLength = UTF8CharLength(c);
|
||||
if (utf8CharLength > 1) {
|
||||
Line::Flags flags(0);
|
||||
flags.mValue = mLines[currentLine].mFlags[currentIndex];
|
||||
for (int j = 1; j < utf8CharLength; j++) {
|
||||
currentIndex++;
|
||||
mLines[currentLine].mFlags[currentIndex] = flags.mValue;
|
||||
}
|
||||
}
|
||||
currentIndex++;
|
||||
}
|
||||
withinNotDef = !ifDefs.back();
|
||||
// }
|
||||
// mUpdateFlags = false;
|
||||
currentIndex++;
|
||||
}
|
||||
withinNotDef = !ifDefs.back();
|
||||
}
|
||||
mDefines.clear();
|
||||
}
|
||||
|
||||
@@ -1037,6 +1037,7 @@
|
||||
"hex.builtin.view.pattern_editor.shortcut.move_home": "Move Cursor to the Start of the Line",
|
||||
"hex.builtin.view.pattern_editor.shortcut.move_end": "Move Cursor to the End of the Line",
|
||||
"hex.builtin.view.pattern_editor.shortcut.move_top": "Move Cursor to the Start of the File",
|
||||
"hex.builtin.view.pattern_editor.shortcut.move_matched_bracket": "Move Cursor to the Matching Bracket",
|
||||
"hex.builtin.view.pattern_editor.shortcut.move_bottom": "Move Cursor to the End of the File",
|
||||
"hex.builtin.view.pattern_editor.shortcut.delete_word_left": "Delete One Word to the Left of the Cursor",
|
||||
"hex.builtin.view.pattern_editor.shortcut.delete_word_right": "Delete One Word to the Right of the Cursor",
|
||||
|
||||
@@ -2513,6 +2513,11 @@ namespace hex::plugin::builtin {
|
||||
editor->MoveEnd(false);
|
||||
});
|
||||
|
||||
ShortcutManager::addShortcut(this, CTRLCMD + SHIFT + Keys::M + AllowWhileTyping, "hex.builtin.view.pattern_editor.shortcut.move_matched_bracket", [this] {
|
||||
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr)
|
||||
editor->MoveToMatchedBracket(false);
|
||||
});
|
||||
|
||||
ShortcutManager::addShortcut(this, Keys::F8 + AllowWhileTyping, "hex.builtin.view.pattern_editor.shortcut.add_breakpoint", [this] {
|
||||
const auto line = m_textEditor.get(ImHexApi::Provider::get()).GetCursorPosition().mLine + 1;
|
||||
const auto &runtime = ContentRegistry::PatternLanguage::getRuntime();
|
||||
|
||||
Reference in New Issue
Block a user