Skip to content

Commit

Permalink
impr: Various fixes and an enhancement for the pattern editor (#1528)
Browse files Browse the repository at this point in the history
Fixed console error messages using doc comment syntax highlights. Fixed
results of find not updating when march case was toggled. Fixed syntax
highlights of nested ifdefs. Fixed editor cursor blinks if OS focus goes
to another window. Fixed Highlights of "\\\"" was incorrectly handled.

---------

Co-authored-by: Nik <werwolv98@gmail.com>
  • Loading branch information
paxcut and WerWolv authored Mar 21, 2024
1 parent f5987fd commit 3b37011
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 93 deletions.
2 changes: 1 addition & 1 deletion lib/third_party/imgui/ColorTextEditor/include/TextEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ class TextEditor
bool mCaseSensitive;

LanguageDefinition()
: mGlobalDocComment("/*!"), mDocComment("/**"), mPreprocChar('#'), mAutoIndentation(true), mTokenize(nullptr), mCaseSensitive(true)
: mPreprocChar('#'), mAutoIndentation(true), mTokenize(nullptr), mCaseSensitive(true)
{
}

Expand Down
123 changes: 65 additions & 58 deletions lib/third_party/imgui/ColorTextEditor/source/TextEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,7 @@ ImU32 TextEditor::GetGlyphColor(const Glyph &aGlyph) const {
return mPalette[(int)PaletteIndex::Comment];
if (aGlyph.mMultiLineComment)
return mPalette[(int)PaletteIndex::MultiLineComment];
if (aGlyph.mDeactivated && !aGlyph.mPreprocessor)
if (aGlyph.mDeactivated)
return mPalette[(int)PaletteIndex::PreprocessorDeactivated];
auto const color = mPalette[(int)aGlyph.mColorIndex];
if (aGlyph.mPreprocessor) {
Expand All @@ -619,10 +619,20 @@ ImU32 TextEditor::GetGlyphColor(const Glyph &aGlyph) const {
}

void TextEditor::HandleKeyboardInputs() {
ImGuiIO &io = ImGui::GetIO();
auto shift = io.KeyShift;
auto ctrl = io.ConfigMacOSXBehaviors ? io.KeySuper : io.KeyCtrl;
auto alt = io.ConfigMacOSXBehaviors ? io.KeyCtrl : io.KeyAlt;
ImGuiIO &io = ImGui::GetIO();
auto shift = io.KeyShift;
auto left = ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_LeftArrow));
auto right = ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_RightArrow));
auto up = ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow));
auto down = ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow));
auto ctrl = io.ConfigMacOSXBehaviors ? io.KeyAlt : io.KeyCtrl;
auto alt = io.ConfigMacOSXBehaviors ? io.KeyCtrl : io.KeyAlt;
auto home = io.ConfigMacOSXBehaviors ? io.KeySuper && left : ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Home));
auto end = io.ConfigMacOSXBehaviors ? io.KeySuper && right : ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_End));
auto top = io.ConfigMacOSXBehaviors ? io.KeySuper && up : ctrl && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Home));
auto bottom = io.ConfigMacOSXBehaviors ? io.KeySuper && down : ctrl && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_End));
auto pageUp = io.ConfigMacOSXBehaviors ? ctrl && up : ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageUp));
auto pageDown = io.ConfigMacOSXBehaviors ? ctrl && down : ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageDown));

if (ImGui::IsWindowFocused()) {
if (ImGui::IsWindowHovered())
Expand All @@ -638,25 +648,25 @@ void TextEditor::HandleKeyboardInputs() {
Undo();
else if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Y)))
Redo();
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)))
else if (!ctrl && !alt && up)
MoveUp(1, shift);
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow)))
else if (!ctrl && !alt && down)
MoveDown(1, shift);
else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_LeftArrow)))
else if (!alt && left)
MoveLeft(1, shift, ctrl);
else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_RightArrow)))
else if (!alt && right)
MoveRight(1, shift, ctrl);
else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageUp)))
else if (!alt && pageUp)
MoveUp(GetPageSize() - 4, shift);
else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageDown)))
else if (!alt && pageDown)
MoveDown(GetPageSize() - 4, shift);
else if (!alt && ctrl && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Home)))
else if (!alt && top)
MoveTop(shift);
else if (ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_End)))
else if (!alt && bottom)
MoveBottom(shift);
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Home)))
else if (!ctrl && !alt && home)
MoveHome(shift);
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_End)))
else if (!ctrl && !alt && end)
MoveEnd(shift);
else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete)))
Delete();
Expand Down Expand Up @@ -722,7 +732,7 @@ void TextEditor::HandleKeyboardInputs() {
void TextEditor::HandleMouseInputs() {
ImGuiIO &io = ImGui::GetIO();
auto shift = io.KeyShift;
auto ctrl = io.ConfigMacOSXBehaviors ? io.KeySuper : io.KeyCtrl;
auto ctrl = io.ConfigMacOSXBehaviors ? io.KeyAlt : io.KeyCtrl;
auto alt = io.ConfigMacOSXBehaviors ? io.KeyCtrl : io.KeyAlt;

if (ImGui::IsWindowHovered()) {
Expand Down Expand Up @@ -905,7 +915,10 @@ void TextEditor::Render() {
}

if (mState.mCursorPosition.mLine == lineNo && mShowCursor) {
auto focused = ImGui::IsWindowFocused();
bool focused = false;
ImGuiViewport *viewport = ImGui::GetWindowViewport();
if (viewport->PlatformUserData != NULL && ImGui::GetPlatformIO().Platform_GetWindowFocus(viewport))
focused = ImGui::IsWindowFocused();

// Highlight the current line (where the cursor is)
if (!HasSelection()) {
Expand Down Expand Up @@ -2505,6 +2518,7 @@ void TextEditor::ColorizeInternal() {
auto firstChar = true; // there is no other non-whitespace characters in the line before
auto currentLine = 0;
auto currentIndex = 0;
auto commentLength = 0;
auto &startStr = mLanguageDefinition.mCommentStart;
auto &singleStartStr = mLanguageDefinition.mSingleLineComment;
auto &docStartStr = mLanguageDefinition.mDocComment;
Expand All @@ -2516,6 +2530,14 @@ void TextEditor::ColorizeInternal() {
while (currentLine < endLine || currentIndex < endIndex) {
auto &line = mLines[currentLine];

auto setGlyphFlags = [&](int index) {
line[index].mMultiLineComment = withinComment;
line[index].mComment = withinSingleLineComment;
line[index].mDocComment = withinDocComment;
line[index].mGlobalDocComment = withinGlobalDocComment;
line[index].mDeactivated = withinNotDef;
};

if (currentIndex == 0) {
withinSingleLineComment = false;
withinPreproc = false;
Expand All @@ -2532,24 +2554,12 @@ void TextEditor::ColorizeInternal() {
bool inComment = (commentStartLine < currentLine || (commentStartLine == currentLine && commentStartIndex <= currentIndex));

if (withinString) {
line[currentIndex].mMultiLineComment = withinComment;
line[currentIndex].mComment = withinSingleLineComment;
line[currentIndex].mDocComment = withinDocComment;
line[currentIndex].mGlobalDocComment = withinGlobalDocComment;
line[currentIndex].mDeactivated = withinNotDef;
if (c == '\"') {
if (currentIndex > 2 && line[currentIndex - 1].mChar == '\\' && line[currentIndex - 2].mChar != '\\') {
currentIndex += 1;
if (currentIndex < (int)line.size()) {
line[currentIndex].mMultiLineComment = withinComment;
line[currentIndex].mComment = withinSingleLineComment;
line[currentIndex].mDocComment = withinDocComment;
line[currentIndex].mGlobalDocComment = withinGlobalDocComment;
line[currentIndex].mDeactivated = withinNotDef;
}
} else
withinString = false;
}
setGlyphFlags(currentIndex);
if (c == '\\') {
currentIndex++;
setGlyphFlags(currentIndex);
} else if (c == '\"')
withinString = false;
} else {
if (firstChar && c == mLanguageDefinition.mPreprocChar) {
withinPreproc = true;
Expand Down Expand Up @@ -2594,7 +2604,6 @@ void TextEditor::ColorizeInternal() {
}
if (!withinNotDef) {
bool isConditionMet = std::find(mDefines.begin(),mDefines.end(),identifier) != mDefines.end();
withinNotDef = !isConditionMet;
ifDefs.push_back(isConditionMet);
} else
ifDefs.push_back(false);
Expand All @@ -2608,28 +2617,24 @@ void TextEditor::ColorizeInternal() {
}
if (!withinNotDef) {
bool isConditionMet = std::find(mDefines.begin(),mDefines.end(),identifier) == mDefines.end();
withinNotDef = !isConditionMet;
ifDefs.push_back(isConditionMet);
} else
ifDefs.push_back(false);
}
}
} else {
if (directive == "endif") {
if (ifDefs.size() > 1)
if (ifDefs.size() > 1) {
ifDefs.pop_back();
withinNotDef = !ifDefs.back();
withinNotDef = !ifDefs.back();
}
}
}
}

if (c == '\"') {
withinString = true;
line[currentIndex].mMultiLineComment = withinComment;
line[currentIndex].mComment = withinSingleLineComment;
line[currentIndex].mDocComment = withinDocComment;
line[currentIndex].mGlobalDocComment = withinGlobalDocComment;
line[currentIndex].mDeactivated = withinNotDef;
setGlyphFlags(currentIndex);
} else {
auto pred = [](const char &a, const Glyph &b) { return a == b.mChar; };

Expand All @@ -2653,29 +2658,30 @@ void TextEditor::ColorizeInternal() {
if (isGlobalDocComment || isDocComment || isComment) {
commentStartLine = currentLine;
commentStartIndex = currentIndex;
if (isGlobalDocComment)
if (isGlobalDocComment) {
withinGlobalDocComment = true;
else if (isDocComment)
commentLength = 3;
} else if (isDocComment) {
withinDocComment = true;
else
commentLength = 3;
} else {
withinComment = true;
commentLength = 2;
}
}
}
inComment = (commentStartLine < currentLine || (commentStartLine == currentLine && commentStartIndex <= currentIndex));
}
line[currentIndex].mGlobalDocComment = withinGlobalDocComment;
line[currentIndex].mDocComment = withinDocComment;
line[currentIndex].mMultiLineComment = withinComment;
line[currentIndex].mComment = withinSingleLineComment;
line[currentIndex].mDeactivated = withinNotDef;
setGlyphFlags(currentIndex);

auto &endStr = mLanguageDefinition.mCommentEnd;
if (compareBack(endStr, line)) {
withinComment = false;
withinDocComment = false;
withinGlobalDocComment = false;
commentStartLine = endLine;
commentStartIndex = endIndex;
if (compareBack(endStr, line) && ((commentStartLine != currentLine) || (commentStartIndex + commentLength < currentIndex))) {
withinComment = false;
withinDocComment = false;
withinGlobalDocComment = false;
commentStartLine = endLine;
commentStartIndex = endIndex;
commentLength = 0;
}
}
}
Expand All @@ -2684,6 +2690,7 @@ void TextEditor::ColorizeInternal() {

currentIndex += UTF8CharLength(c);
if (currentIndex >= (int)line.size()) {
withinNotDef = !ifDefs.back();
currentIndex = 0;
++currentLine;
}
Expand Down
35 changes: 35 additions & 0 deletions plugins/builtin/include/content/views/view_pattern_editor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#include <functional>

#include <TextEditor.h>
#include "popups/popup_file_chooser.hpp"
#include "hex/api/achievement_manager.hpp"

namespace pl::ptrn { class Pattern; }

Expand Down Expand Up @@ -255,6 +257,39 @@ namespace hex::plugin::builtin {
void registerMenuItems();
void registerHandlers();

std::function<void()> importPatternFile = [&] {
auto provider = ImHexApi::Provider::get();
const auto basePaths = fs::getDefaultPaths(fs::ImHexPath::Patterns);
std::vector<std::fs::path> paths;

for (const auto &imhexPath : basePaths) {
if (!wolv::io::fs::exists(imhexPath)) continue;

std::error_code error;
for (auto &entry : std::fs::recursive_directory_iterator(imhexPath, error)) {
if (entry.is_regular_file() && entry.path().extension() == ".hexpat")
paths.push_back(entry.path());
}
}
ui::PopupFileChooser::open(
basePaths, paths, std::vector<hex::fs::ItemFilter>{ { "Pattern File", "hexpat" } }, false,
[this, provider](const std::fs::path &path) {
this->loadPatternFile(path, provider);
AchievementManager::unlockAchievement("hex.builtin.achievement.patterns", "hex.builtin.achievement.patterns.load_existing.name");
}
);
};

std::function<void()> exportPatternFile = [&] {
fs::openFileBrowser(
fs::DialogMode::Save, { {"Pattern", "hexpat"} },
[this](const auto &path) {
wolv::io::File file(path, wolv::io::File::Mode::Create);
file.writeString(wolv::util::trim(m_textEditor.GetText()));
}
);
};

void appendEditorText(const std::string &text);
void appendVariable(const std::string &type);
void appendArray(const std::string &type, size_t size);
Expand Down
2 changes: 2 additions & 0 deletions plugins/builtin/romfs/lang/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@
"hex.builtin.menu.file.export.ips32": "IPS32 Patch",
"hex.builtin.menu.file.export.bookmark": "Bookmark",
"hex.builtin.menu.file.export.pattern": "Pattern File",
"hex.builtin.menu.file.export.pattern_file": "Export pattern File",
"hex.builtin.menu.file.export.data_processor": "Data Processor Workspace",
"hex.builtin.menu.file.export.popup.create": "Cannot export data. Failed to create file!",
"hex.builtin.menu.file.export.report": "Report",
Expand All @@ -147,6 +148,7 @@
"hex.builtin.menu.file.import.modified_file": "Modified File",
"hex.builtin.menu.file.import.bookmark": "Bookmark",
"hex.builtin.menu.file.import.pattern": "Pattern File",
"hex.builtin.menu.file.import.pattern_file": "Import pattern File",
"hex.builtin.menu.file.import.data_processor": "Data Processor Workspace",
"hex.builtin.menu.file.import.custom_encoding": "Custom Encoding File",
"hex.builtin.menu.file.import.modified_file.popup.invalid_size": "File selected do not have the same size as the current file. Both sizes must match",
Expand Down
Loading

0 comments on commit 3b37011

Please sign in to comment.