1
0
mirror of synced 2025-01-31 03:53:44 +01:00

ui: Make pattern editor console use another text editor

This commit is contained in:
WerWolv 2023-06-13 22:58:57 +02:00
parent 5c31b5cf0d
commit dd832bfa7e
4 changed files with 81 additions and 54 deletions

View File

@ -212,6 +212,9 @@ public:
bool IsTextChanged() const { return mTextChanged; } bool IsTextChanged() const { return mTextChanged; }
bool IsCursorPositionChanged() const { return mCursorPositionChanged; } bool IsCursorPositionChanged() const { return mCursorPositionChanged; }
void SetShowCursor(bool aValue) { mShowCursor = aValue; }
void SetShowLineNumbers(bool aValue) { mShowLineNumbers = aValue; }
bool IsColorizerEnabled() const { return mColorizerEnabled; } bool IsColorizerEnabled() const { return mColorizerEnabled; }
void SetColorizerEnable(bool aValue); void SetColorizerEnable(bool aValue);
@ -386,6 +389,8 @@ private:
uint64_t mStartTime; uint64_t mStartTime;
float mLastClick; float mLastClick;
bool mShowCursor;
bool mShowLineNumbers;
}; };
bool TokenizeCStyleString(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end); bool TokenizeCStyleString(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end);

View File

@ -24,7 +24,7 @@ bool equals(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Bi
TextEditor::Palette TextEditor::sPaletteBase = TextEditor::GetDarkPalette(); TextEditor::Palette TextEditor::sPaletteBase = TextEditor::GetDarkPalette();
TextEditor::TextEditor() 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::milliseconds>(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::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count()) {
SetLanguageDefinition(LanguageDefinition::HLSL()); SetLanguageDefinition(LanguageDefinition::HLSL());
mLines.push_back(Line()); 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 // Deduce mTextStart by evaluating mLines size (global lineMax) plus two spaces as text width
char buf[16]; 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; mTextStart = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, buf, nullptr, nullptr).x + mLeftMargin;
if (!mLines.empty()) { 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]); 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(); auto focused = ImGui::IsWindowFocused();
// Highlight the current line (where the cursor is) // Highlight the current line (where the cursor is)

View File

@ -139,7 +139,7 @@ namespace hex::plugin::builtin {
bool m_hasUnevaluatedChanges = false; bool m_hasUnevaluatedChanges = false;
TextEditor m_textEditor; TextEditor m_textEditor, m_consoleEditor;
std::atomic<bool> m_dangerousFunctionCalled = false; std::atomic<bool> m_dangerousFunctionCalled = false;
std::atomic<DangerousFunctionPerms> m_dangerousFunctionsAllowed = DangerousFunctionPerms::Ask; std::atomic<DangerousFunctionPerms> m_dangerousFunctionsAllowed = DangerousFunctionPerms::Ask;
@ -152,7 +152,7 @@ namespace hex::plugin::builtin {
ui::HexEditor m_sectionHexEditor; ui::HexEditor m_sectionHexEditor;
PerProvider<std::string> m_sourceCode; PerProvider<std::string> m_sourceCode;
PerProvider<std::vector<std::pair<pl::core::LogConsole::Level, std::string>>> m_console; PerProvider<std::vector<std::string>> m_console;
PerProvider<bool> m_executionDone = true; PerProvider<bool> m_executionDone = true;
std::mutex m_logMutex; std::mutex m_logMutex;
@ -170,7 +170,7 @@ namespace hex::plugin::builtin {
std::atomic<bool> m_resetDebuggerVariables; std::atomic<bool> m_resetDebuggerVariables;
private: private:
void drawConsole(ImVec2 size, const std::vector<std::pair<pl::core::LogConsole::Level, std::string>> &console); void drawConsole(ImVec2 size);
void drawEnvVars(ImVec2 size, std::list<EnvVar> &envVars); void drawEnvVars(ImVec2 size, std::list<EnvVar> &envVars);
void drawVariableSettings(ImVec2 size, std::map<std::string, PatternVariable> &patternVariables); void drawVariableSettings(ImVec2 size, std::map<std::string, PatternVariable> &patternVariables);
void drawSectionSelector(ImVec2 size, std::map<u64, pl::api::Section> &sections); void drawSectionSelector(ImVec2 size, std::map<u64, pl::api::Section> &sections);

View File

@ -83,6 +83,41 @@ namespace hex::plugin::builtin {
initialized = true; 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; return langDef;
} }
@ -93,6 +128,12 @@ namespace hex::plugin::builtin {
this->m_textEditor.SetLanguageDefinition(PatternLanguage()); this->m_textEditor.SetLanguageDefinition(PatternLanguage());
this->m_textEditor.SetShowWhitespaces(false); 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->registerEvents();
this->registerMenuItems(); this->registerMenuItems();
this->registerHandlers(); this->registerHandlers();
@ -101,7 +142,6 @@ namespace hex::plugin::builtin {
ViewPatternEditor::~ViewPatternEditor() { ViewPatternEditor::~ViewPatternEditor() {
EventManager::unsubscribe<RequestSetPatternLanguageCode>(this); EventManager::unsubscribe<RequestSetPatternLanguageCode>(this);
EventManager::unsubscribe<EventFileLoaded>(this); EventManager::unsubscribe<EventFileLoaded>(this);
EventManager::unsubscribe<RequestChangeTheme>(this);
EventManager::unsubscribe<EventProviderChanged>(this); EventManager::unsubscribe<EventProviderChanged>(this);
EventManager::unsubscribe<EventProviderClosed>(this); EventManager::unsubscribe<EventProviderClosed>(this);
} }
@ -146,7 +186,7 @@ namespace hex::plugin::builtin {
if (ImGui::BeginTabBar("##settings")) { if (ImGui::BeginTabBar("##settings")) {
if (ImGui::BeginTabItem("hex.builtin.view.pattern_editor.console"_lang)) { if (ImGui::BeginTabItem("hex.builtin.view.pattern_editor.console"_lang)) {
this->drawConsole(settingsSize, *this->m_console); this->drawConsole(settingsSize);
ImGui::EndTabItem(); ImGui::EndTabItem();
} }
if (ImGui::BeginTabItem("hex.builtin.view.pattern_editor.env_vars"_lang)) { if (ImGui::BeginTabItem("hex.builtin.view.pattern_editor.env_vars"_lang)) {
@ -257,47 +297,9 @@ namespace hex::plugin::builtin {
ImGui::End(); ImGui::End();
} }
void ViewPatternEditor::drawConsole(ImVec2 size, const std::vector<std::pair<pl::core::LogConsole::Level, std::string>> &console) { void ViewPatternEditor::drawConsole(ImVec2 size) {
const auto &palette = TextEditor::GetPalette(); this->m_consoleEditor.Render("##console", size, true);
ImGui::PushStyleColor(ImGuiCol_ChildBg, palette[u32(TextEditor::PaletteIndex::Background)]); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetStyle().FramePadding.y + 1_scaled);
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::drawEnvVars(ImVec2 size, std::list<EnvVar> &envVars) { void ViewPatternEditor::drawEnvVars(ImVec2 size, std::list<EnvVar> &envVars) {
@ -898,7 +900,21 @@ namespace hex::plugin::builtin {
runtime.setLogCallback([this](auto level, auto message) { runtime.setLogCallback([this](auto level, auto message) {
std::scoped_lock lock(this->m_logMutex); 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 { ON_SCOPE_EXIT {
@ -911,9 +927,9 @@ namespace hex::plugin::builtin {
std::scoped_lock lock(this->m_logMutex); std::scoped_lock lock(this->m_logMutex);
this->m_console->emplace_back( this->m_console->emplace_back(
pl::core::LogConsole::Level::Info, hex::format("I: Evaluation took {}", runtime.getLastRunningTime())
hex::format("Evaluation took {}", runtime.getLastRunningTime())
); );
this->m_consoleEditor.SetTextLines(this->m_console.get());
}; };
@ -958,8 +974,10 @@ namespace hex::plugin::builtin {
if (oldProvider != nullptr) if (oldProvider != nullptr)
this->m_sourceCode.get(oldProvider) = this->m_textEditor.GetText(); 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))); this->m_textEditor.SetText(wolv::util::trim(this->m_sourceCode.get(newProvider)));
}
else else
this->m_textEditor.SetText(""); this->m_textEditor.SetText("");
} else { } else {