Fix segfault when opening recent file with pattern sync; Don't show p… (#2448)

…attern selection popup when pattern is already open

This PR does two things. Most importantly, it fixes a segfault that can
be caused by opening a recent file with pattern sync enabled.
Secondly, it makes it so that the pattern selection popup does not
appear if you already have text in the pattern editor for a given
provider (due to CLI args, a project file, pattern sync, etc.). If you
open a file normally, that text field is empty and the popup will appear
so you can select a pre-made pattern like usual.
This commit is contained in:
Zackary Newman 2025-09-14 00:10:38 -04:00 committed by GitHub
parent f08b182bf2
commit 67efea6444
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 110 additions and 82 deletions

View File

@ -40,8 +40,12 @@ namespace hex::plugin::builtin {
return &m_editorRuntime; return &m_editorRuntime;
} }
ui::TextEditor &getTextEditor() { ui::TextEditor *getTextEditor() {
return m_textEditor; auto provider = ImHexApi::Provider::get();
if (provider == nullptr)
return nullptr;
return &m_textEditor.get(provider);
} }
bool getChangesWereParsed() const { bool getChangesWereParsed() const {

View File

@ -1252,7 +1252,11 @@ namespace hex::plugin::builtin {
} }
} }
} }
m_viewPatternEditor->getTextEditor().setErrorMarkers(errorMarkers); ui::TextEditor *editor = m_viewPatternEditor->getTextEditor();
if (editor != nullptr)
editor->setErrorMarkers(errorMarkers);
else
log::warn("Text editor not found, provider is null");
} }
// creates a map from variable names to a vector of token indices // creates a map from variable names to a vector of token indices
@ -1590,7 +1594,11 @@ namespace hex::plugin::builtin {
lineOfColors[tokenOffset + j] = color; lineOfColors[tokenOffset + j] = color;
} }
} }
m_viewPatternEditor->getTextEditor().setColorizedLine(line, lineOfColors); ui::TextEditor *editor = m_viewPatternEditor->getTextEditor();
if (editor != nullptr)
editor->setColorizedLine(line, lineOfColors);
else
log::warn("Text editor not found, provider is null");
} }
} }
@ -1918,8 +1926,13 @@ namespace hex::plugin::builtin {
if (!m_lines.empty()) if (!m_lines.empty())
m_lines.clear(); m_lines.clear();
if (m_text.empty()) if (m_text.empty()) {
m_text = m_viewPatternEditor->getTextEditor().getText(); ui::TextEditor *editor = m_viewPatternEditor->getTextEditor();
if (editor != nullptr)
m_text = editor->getText();
else
log::warn("Text editor not found, provider is null");
}
m_lines = wolv::util::splitString(m_text, "\n"); m_lines = wolv::util::splitString(m_text, "\n");
m_lines.push_back(""); m_lines.push_back("");
@ -2248,72 +2261,85 @@ namespace hex::plugin::builtin {
} }
}; };
try { try {
m_runningColorizers++; m_runningColorizers++;
auto preprocessor = patternLanguage->get()->getInternals().preprocessor.get(); auto preprocessor = patternLanguage->get()->getInternals().preprocessor.get();
auto parser = patternLanguage->get()->getInternals().parser.get(); auto parser = patternLanguage->get()->getInternals().parser.get();
using Types = std::map<std::string, pl::hlp::safe_shared_ptr<pl::core::ast::ASTNodeTypeDecl>>; using Types = std::map<std::string, pl::hlp::safe_shared_ptr<pl::core::ast::ASTNodeTypeDecl>>;
Types types = parser->getTypes(); Types types = parser->getTypes();
if (!m_UDTs.empty()) if (!m_UDTs.empty())
m_UDTs.clear(); m_UDTs.clear();
for (auto &[name, type]: types) for (auto &[name, type]: types)
m_UDTs.push_back(name); m_UDTs.push_back(name);
// Namespaces from included files. // Namespaces from included files.
m_nameSpaces.clear(); m_nameSpaces.clear();
m_nameSpaces = preprocessor->getNamespaces(); m_nameSpaces = preprocessor->getNamespaces();
clearVariables(); clearVariables();
m_parsedImports = preprocessor->getParsedImports();
for (auto &[name, tokens]: m_parsedImports) {
m_tokens = tokens;
m_text = tokens[0].location.source->content;
if (m_text.empty() || m_text == "\n")
return;
loadText();
processSource();
if (!m_tokenColors.empty())
m_tokenColors.clear();
}
m_tokens = preprocessor->getResult();
if (m_tokens.empty())
return;
if (!m_globalTokenRange.empty())
m_globalTokenRange.clear();
m_globalTokenRange.insert(Interval(0, m_tokens.size()-1));
ui::TextEditor *editor = m_viewPatternEditor->getTextEditor();
if (editor != nullptr)
m_text = editor->getText();
else
log::warn("Text editor not found, provider is null");
m_parsedImports = preprocessor->getParsedImports();
for (auto &[name, tokens]: m_parsedImports) {
m_tokens = tokens;
m_text = tokens[0].location.source->content;
if (m_text.empty() || m_text == "\n") if (m_text.empty() || m_text == "\n")
return; return;
loadText(); loadText();
processSource();
if (!m_tokenColors.empty())
m_tokenColors.clear();
}
m_tokens = preprocessor->getResult(); getAllTokenRanges(IdentifierType::NameSpace);
if (m_tokens.empty()) getAllTokenRanges(IdentifierType::UDT);
return; getAllTokenRanges(IdentifierType::Function);
getGlobalTokenRanges();
fixGlobalVariables();
setInitialColors();
loadInstances();
getAllTokenRanges(IdentifierType::Attribute);
getDefinitions();
fixAutos();
fixChains();
if (!m_globalTokenRange.empty()) m_excludedLocations = preprocessor->getExcludedLocations();
m_globalTokenRange.clear();
m_globalTokenRange.insert(Interval(0, m_tokens.size()-1));
m_text = m_viewPatternEditor->getTextEditor().getText(); colorRemainingIdentifierTokens();
setRequestedIdentifierColors();
if (m_text.empty() || m_text == "\n") editor = m_viewPatternEditor->getTextEditor();
return; if (editor != nullptr)
loadText(); editor->clearErrorMarkers();
else
log::warn("Text editor not found, provider is null");
m_compileErrors = patternLanguage->get()->getCompileErrors();
getAllTokenRanges(IdentifierType::NameSpace); if (!m_compileErrors.empty())
getAllTokenRanges(IdentifierType::UDT); renderErrors();
getAllTokenRanges(IdentifierType::Function); else {
getGlobalTokenRanges(); editor = m_viewPatternEditor->getTextEditor();
fixGlobalVariables(); if (editor != nullptr)
setInitialColors(); editor->clearErrorMarkers();
loadInstances(); else
getAllTokenRanges(IdentifierType::Attribute); log::warn("Text editor not found, provider is null");
getDefinitions(); }
fixAutos();
fixChains();
m_excludedLocations = preprocessor->getExcludedLocations();
colorRemainingIdentifierTokens();
setRequestedIdentifierColors();
m_viewPatternEditor->getTextEditor().clearErrorMarkers();
m_compileErrors = patternLanguage->get()->getCompileErrors();
if (!m_compileErrors.empty())
renderErrors();
else
m_viewPatternEditor->getTextEditor().clearErrorMarkers();
} catch (const std::out_of_range &e) { } catch (const std::out_of_range &e) {
log::debug("TextHighlighter::highlightSourceCode: Out of range error: {}", e.what()); log::debug("TextHighlighter::highlightSourceCode: Out of range error: {}", e.what());
m_wasInterrupted = true; m_wasInterrupted = true;
@ -2321,4 +2347,4 @@ namespace hex::plugin::builtin {
} }
return; return;
} }
} }

View File

@ -45,6 +45,7 @@
#include <fonts/fonts.hpp> #include <fonts/fonts.hpp>
#include <hex/api/events/requests_gui.hpp> #include <hex/api/events/requests_gui.hpp>
#include <hex/helpers/menu_items.hpp> #include <hex/helpers/menu_items.hpp>
#include <hex/helpers/logger.hpp>
namespace hex::plugin::builtin { namespace hex::plugin::builtin {
@ -70,6 +71,16 @@ namespace hex::plugin::builtin {
return; return;
} }
ui::TextEditor *editor = m_view->getTextEditor();
if (editor != nullptr) {
if (!editor->isEmpty()) {
this->close();
return;
}
} else {
log::warn("Text editor not found, provider is null");
}
ImGuiExt::TextFormattedWrapped("{}", static_cast<const char *>("hex.builtin.view.pattern_editor.accept_pattern.desc"_lang)); ImGuiExt::TextFormattedWrapped("{}", static_cast<const char *>("hex.builtin.view.pattern_editor.accept_pattern.desc"_lang));
if (ImGui::BeginListBox("##patterns_accept", ImVec2(400_scaled, 0))) { if (ImGui::BeginListBox("##patterns_accept", ImVec2(400_scaled, 0))) {

View File

@ -1,5 +1,6 @@
#include <ui/text_editor.hpp> #include <ui/text_editor.hpp>
#include <hex/helpers/utils.hpp> #include <hex/helpers/utils.hpp>
#include <hex/helpers/logger.hpp>
#include <algorithm> #include <algorithm>
namespace hex::ui { namespace hex::ui {
@ -50,8 +51,11 @@ namespace hex::ui {
std::smatch results; std::smatch results;
std::string id; std::string id;
if (m_languageDefinition.m_tokenize == nullptr) if (m_languageDefinition.m_tokenize == nullptr) {
m_languageDefinition.m_tokenize = [](strConstIter, strConstIter, strConstIter &, strConstIter &, PaletteIndex &) { return false; }; m_languageDefinition.m_tokenize = [](strConstIter, strConstIter, strConstIter &, strConstIter &, PaletteIndex &) { return false; };
log::warn("Syntax highlighting tokenize callback is nullptr");
return;
}
i32 linesSize = m_lines.size(); i32 linesSize = m_lines.size();
for (i32 i = 0; i < linesSize; ++i) { for (i32 i = 0; i < linesSize; ++i) {
auto &line = m_lines[i]; auto &line = m_lines[i];
@ -74,28 +78,11 @@ namespace hex::ui {
PaletteIndex token_color = PaletteIndex::Default; PaletteIndex token_color = PaletteIndex::Default;
bool hasTokenizeResult = m_languageDefinition.m_tokenize(current.m_charsIter, last.m_charsIter, token_begin, token_end, token_color); bool hasTokenizeResult = m_languageDefinition.m_tokenize(current.m_charsIter, last.m_charsIter, token_begin, token_end, token_color);
auto token_offset = token_begin - first.m_charsIter;
if (!hasTokenizeResult) {
// todo : remove
// printf("using regex for %.*s\n", first + 10 < last ? 10 : i32(last - first), first);
for (auto &p: m_regexList) {
if (std::regex_search(first.m_charsIter, last.m_charsIter, results, p.first, std::regex_constants::match_continuous)) {
hasTokenizeResult = true;
const auto &v = results.begin();
token_begin = v->first;
token_end = v->second;
token_color = p.second;
break;
}
}
}
if (!hasTokenizeResult) if (!hasTokenizeResult)
current = current + 1; current = current + 1;
else { else {
auto token_offset = token_begin - first.m_charsIter;
current = first + token_offset; current = first + token_offset;
u64 token_length = 0; u64 token_length = 0;
Line::Flags flags(0); Line::Flags flags(0);
@ -1181,4 +1168,4 @@ namespace hex::ui {
return false; return false;
} }
} }