diff --git a/lib/external/imgui/include/TextEditor.h b/lib/external/imgui/include/TextEditor.h index 61fa48618..85f206d5f 100644 --- a/lib/external/imgui/include/TextEditor.h +++ b/lib/external/imgui/include/TextEditor.h @@ -212,6 +212,9 @@ public: bool IsTextChanged() const { return mTextChanged; } bool IsCursorPositionChanged() const { return mCursorPositionChanged; } + void SetShowCursor(bool aValue) { mShowCursor = aValue; } + void SetShowLineNumbers(bool aValue) { mShowLineNumbers = aValue; } + bool IsColorizerEnabled() const { return mColorizerEnabled; } void SetColorizerEnable(bool aValue); @@ -386,6 +389,8 @@ private: uint64_t mStartTime; float mLastClick; + bool mShowCursor; + bool mShowLineNumbers; }; bool TokenizeCStyleString(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end); diff --git a/lib/external/imgui/source/TextEditor.cpp b/lib/external/imgui/source/TextEditor.cpp index 2de3e225c..42be73cfe 100644 --- a/lib/external/imgui/source/TextEditor.cpp +++ b/lib/external/imgui/source/TextEditor.cpp @@ -24,7 +24,7 @@ bool equals(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Bi TextEditor::Palette TextEditor::sPaletteBase = TextEditor::GetDarkPalette(); TextEditor::TextEditor() - : mLineSpacing(1.0f), mUndoIndex(0), mTabSize(4), mOverwrite(false), mReadOnly(false), mWithinRender(false), mScrollToCursor(false), mScrollToTop(false), mTextChanged(false), mColorizerEnabled(true), mTextStart(20.0f), mLeftMargin(10), mCursorPositionChanged(false), mColorRangeMin(0), mColorRangeMax(0), mSelectionMode(SelectionMode::Normal), mCheckComments(true), mLastClick(-1.0f), mHandleKeyboardInputs(true), mHandleMouseInputs(true), mIgnoreImGuiChild(false), mShowWhitespaces(true), mStartTime(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()) { + : mLineSpacing(1.0f), mUndoIndex(0), mTabSize(4), mOverwrite(false), mReadOnly(false), mWithinRender(false), mScrollToCursor(false), mScrollToTop(false), mTextChanged(false), mColorizerEnabled(true), mTextStart(20.0f), mLeftMargin(10), mCursorPositionChanged(false), mColorRangeMin(0), mColorRangeMax(0), mSelectionMode(SelectionMode::Normal), mCheckComments(true), mLastClick(-1.0f), mHandleKeyboardInputs(true), mHandleMouseInputs(true), mIgnoreImGuiChild(false), mShowWhitespaces(true), mShowCursor(true), mShowLineNumbers(true), mStartTime(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()) { SetLanguageDefinition(LanguageDefinition::HLSL()); mLines.push_back(Line()); } @@ -788,7 +788,11 @@ void TextEditor::Render() { // Deduce mTextStart by evaluating mLines size (global lineMax) plus two spaces as text width char buf[16]; - snprintf(buf, 16, " %d ", globalLineMax); + + if (mShowLineNumbers) + snprintf(buf, 16, " %d ", globalLineMax); + else + buf[0] = '\0'; mTextStart = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, buf, nullptr, nullptr).x + mLeftMargin; if (!mLines.empty()) { @@ -859,7 +863,7 @@ void TextEditor::Render() { drawList->AddCircle(start + ImVec2(0, mCharAdvance.y) / 2, mCharAdvance.y / 3, mPalette[(int)PaletteIndex::Default]); } - if (mState.mCursorPosition.mLine == lineNo) { + if (mState.mCursorPosition.mLine == lineNo && mShowCursor) { auto focused = ImGui::IsWindowFocused(); // Highlight the current line (where the cursor is) diff --git a/plugins/builtin/include/content/views/view_pattern_editor.hpp b/plugins/builtin/include/content/views/view_pattern_editor.hpp index 602ca9e92..d388e7f16 100644 --- a/plugins/builtin/include/content/views/view_pattern_editor.hpp +++ b/plugins/builtin/include/content/views/view_pattern_editor.hpp @@ -139,7 +139,7 @@ namespace hex::plugin::builtin { bool m_hasUnevaluatedChanges = false; - TextEditor m_textEditor; + TextEditor m_textEditor, m_consoleEditor; std::atomic m_dangerousFunctionCalled = false; std::atomic m_dangerousFunctionsAllowed = DangerousFunctionPerms::Ask; @@ -152,7 +152,7 @@ namespace hex::plugin::builtin { ui::HexEditor m_sectionHexEditor; PerProvider m_sourceCode; - PerProvider>> m_console; + PerProvider> m_console; PerProvider m_executionDone = true; std::mutex m_logMutex; @@ -170,7 +170,7 @@ namespace hex::plugin::builtin { std::atomic m_resetDebuggerVariables; private: - void drawConsole(ImVec2 size, const std::vector> &console); + void drawConsole(ImVec2 size); void drawEnvVars(ImVec2 size, std::list &envVars); void drawVariableSettings(ImVec2 size, std::map &patternVariables); void drawSectionSelector(ImVec2 size, std::map §ions); diff --git a/plugins/builtin/source/content/views/view_pattern_editor.cpp b/plugins/builtin/source/content/views/view_pattern_editor.cpp index 8e4ec19f3..29913d1f9 100644 --- a/plugins/builtin/source/content/views/view_pattern_editor.cpp +++ b/plugins/builtin/source/content/views/view_pattern_editor.cpp @@ -83,6 +83,41 @@ namespace hex::plugin::builtin { initialized = true; } + + return langDef; + } + + static const TextEditor::LanguageDefinition &ConsoleLog() { + 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; + else + paletteIndex = TextEditor::PaletteIndex::Max; + + outBegin = inBegin; + outEnd = inEnd; + + return true; + }; + + langDef.mName = "Console Log"; + langDef.mCaseSensitive = false; + langDef.mAutoIndentation = false; + langDef.mCommentStart = "\x01"; + langDef.mCommentEnd = "\x01"; + langDef.mSingleLineComment = "\x01"; + + initialized = true; + } return langDef; } @@ -93,6 +128,12 @@ namespace hex::plugin::builtin { this->m_textEditor.SetLanguageDefinition(PatternLanguage()); this->m_textEditor.SetShowWhitespaces(false); + this->m_consoleEditor.SetLanguageDefinition(ConsoleLog()); + this->m_consoleEditor.SetShowWhitespaces(false); + this->m_consoleEditor.SetReadOnly(true); + this->m_consoleEditor.SetShowCursor(false); + this->m_consoleEditor.SetShowLineNumbers(false); + this->registerEvents(); this->registerMenuItems(); this->registerHandlers(); @@ -101,7 +142,6 @@ namespace hex::plugin::builtin { ViewPatternEditor::~ViewPatternEditor() { EventManager::unsubscribe(this); EventManager::unsubscribe(this); - EventManager::unsubscribe(this); EventManager::unsubscribe(this); EventManager::unsubscribe(this); } @@ -135,7 +175,7 @@ namespace hex::plugin::builtin { if (ImGui::IsItemHovered()) { ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNS); } - + if (dragging) { height += ImGui::GetMouseDragDelta(ImGuiMouseButton_Left, 0).y; ImGui::ResetMouseDragDelta(ImGuiMouseButton_Left); @@ -146,7 +186,7 @@ namespace hex::plugin::builtin { if (ImGui::BeginTabBar("##settings")) { if (ImGui::BeginTabItem("hex.builtin.view.pattern_editor.console"_lang)) { - this->drawConsole(settingsSize, *this->m_console); + this->drawConsole(settingsSize); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("hex.builtin.view.pattern_editor.env_vars"_lang)) { @@ -257,47 +297,9 @@ namespace hex::plugin::builtin { ImGui::End(); } - void ViewPatternEditor::drawConsole(ImVec2 size, const std::vector> &console) { - const auto &palette = TextEditor::GetPalette(); - ImGui::PushStyleColor(ImGuiCol_ChildBg, palette[u32(TextEditor::PaletteIndex::Background)]); - if (ImGui::BeginChild("##console", size, true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_HorizontalScrollbar)) { - ImGuiListClipper clipper; - - std::scoped_lock lock(this->m_logMutex); - clipper.Begin(console.size()); - - while (clipper.Step()) - for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { - auto [level, message] = console[i]; - std::replace_if(message.begin(), message.end(), [](char c) { return c == 0x00; }, ' '); - - switch (level) { - using enum pl::core::LogConsole::Level; - - case Debug: - ImGui::PushStyleColor(ImGuiCol_Text, palette[u32(TextEditor::PaletteIndex::Comment)]); - break; - case Info: - ImGui::PushStyleColor(ImGuiCol_Text, palette[u32(TextEditor::PaletteIndex::Default)]); - break; - case Warning: - ImGui::PushStyleColor(ImGuiCol_Text, palette[u32(TextEditor::PaletteIndex::Preprocessor)]); - break; - case Error: - ImGui::PushStyleColor(ImGuiCol_Text, palette[u32(TextEditor::PaletteIndex::ErrorMarker)]); - break; - default: - continue; - } - - if (ImGui::Selectable(hex::format("{}##ConsoleLine", message).c_str())) - ImGui::SetClipboardText(message.c_str()); - - ImGui::PopStyleColor(); - } - } - ImGui::EndChild(); - ImGui::PopStyleColor(1); + void ViewPatternEditor::drawConsole(ImVec2 size) { + this->m_consoleEditor.Render("##console", size, true); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetStyle().FramePadding.y + 1_scaled); } void ViewPatternEditor::drawEnvVars(ImVec2 size, std::list &envVars) { @@ -898,7 +900,21 @@ namespace hex::plugin::builtin { runtime.setLogCallback([this](auto level, auto message) { std::scoped_lock lock(this->m_logMutex); - this->m_console->emplace_back(level, message); + + for (auto line : wolv::util::splitString(message, "\n")) { + switch (level) { + using enum pl::core::LogConsole::Level; + + case Debug: line = hex::format("D: {}", line); break; + case Info: line = hex::format("I: {}", line); break; + case Warning: line = hex::format("W: {}", line); break; + case Error: line = hex::format("E: {}", line); break; + } + + this->m_console->emplace_back(line); + } + + this->m_consoleEditor.SetTextLines(this->m_console.get()); }); ON_SCOPE_EXIT { @@ -911,9 +927,9 @@ namespace hex::plugin::builtin { std::scoped_lock lock(this->m_logMutex); this->m_console->emplace_back( - pl::core::LogConsole::Level::Info, - hex::format("Evaluation took {}", runtime.getLastRunningTime()) + hex::format("I: Evaluation took {}", runtime.getLastRunningTime()) ); + this->m_consoleEditor.SetTextLines(this->m_console.get()); }; @@ -958,8 +974,10 @@ namespace hex::plugin::builtin { if (oldProvider != nullptr) this->m_sourceCode.get(oldProvider) = this->m_textEditor.GetText(); - if (newProvider != nullptr) + if (newProvider != nullptr) { + this->m_consoleEditor.SetTextLines(this->m_console.get(newProvider)); this->m_textEditor.SetText(wolv::util::trim(this->m_sourceCode.get(newProvider))); + } else this->m_textEditor.SetText(""); } else {