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;
}
ui::TextEditor &getTextEditor() {
return m_textEditor;
ui::TextEditor *getTextEditor() {
auto provider = ImHexApi::Provider::get();
if (provider == nullptr)
return nullptr;
return &m_textEditor.get(provider);
}
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
@ -1590,7 +1594,11 @@ namespace hex::plugin::builtin {
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())
m_lines.clear();
if (m_text.empty())
m_text = m_viewPatternEditor->getTextEditor().getText();
if (m_text.empty()) {
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.push_back("");
@ -2248,72 +2261,85 @@ namespace hex::plugin::builtin {
}
};
try {
m_runningColorizers++;
auto preprocessor = patternLanguage->get()->getInternals().preprocessor.get();
auto parser = patternLanguage->get()->getInternals().parser.get();
using Types = std::map<std::string, pl::hlp::safe_shared_ptr<pl::core::ast::ASTNodeTypeDecl>>;
Types types = parser->getTypes();
m_runningColorizers++;
auto preprocessor = patternLanguage->get()->getInternals().preprocessor.get();
auto parser = patternLanguage->get()->getInternals().parser.get();
using Types = std::map<std::string, pl::hlp::safe_shared_ptr<pl::core::ast::ASTNodeTypeDecl>>;
Types types = parser->getTypes();
if (!m_UDTs.empty())
m_UDTs.clear();
for (auto &[name, type]: types)
m_UDTs.push_back(name);
if (!m_UDTs.empty())
m_UDTs.clear();
for (auto &[name, type]: types)
m_UDTs.push_back(name);
// Namespaces from included files.
m_nameSpaces.clear();
m_nameSpaces = preprocessor->getNamespaces();
clearVariables();
// Namespaces from included files.
m_nameSpaces.clear();
m_nameSpaces = preprocessor->getNamespaces();
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")
return;
loadText();
processSource();
if (!m_tokenColors.empty())
m_tokenColors.clear();
}
m_tokens = preprocessor->getResult();
if (m_tokens.empty())
return;
getAllTokenRanges(IdentifierType::NameSpace);
getAllTokenRanges(IdentifierType::UDT);
getAllTokenRanges(IdentifierType::Function);
getGlobalTokenRanges();
fixGlobalVariables();
setInitialColors();
loadInstances();
getAllTokenRanges(IdentifierType::Attribute);
getDefinitions();
fixAutos();
fixChains();
if (!m_globalTokenRange.empty())
m_globalTokenRange.clear();
m_globalTokenRange.insert(Interval(0, m_tokens.size()-1));
m_excludedLocations = preprocessor->getExcludedLocations();
m_text = m_viewPatternEditor->getTextEditor().getText();
colorRemainingIdentifierTokens();
setRequestedIdentifierColors();
if (m_text.empty() || m_text == "\n")
return;
loadText();
editor = m_viewPatternEditor->getTextEditor();
if (editor != nullptr)
editor->clearErrorMarkers();
else
log::warn("Text editor not found, provider is null");
m_compileErrors = patternLanguage->get()->getCompileErrors();
getAllTokenRanges(IdentifierType::NameSpace);
getAllTokenRanges(IdentifierType::UDT);
getAllTokenRanges(IdentifierType::Function);
getGlobalTokenRanges();
fixGlobalVariables();
setInitialColors();
loadInstances();
getAllTokenRanges(IdentifierType::Attribute);
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();
if (!m_compileErrors.empty())
renderErrors();
else {
editor = m_viewPatternEditor->getTextEditor();
if (editor != nullptr)
editor->clearErrorMarkers();
else
log::warn("Text editor not found, provider is null");
}
} catch (const std::out_of_range &e) {
log::debug("TextHighlighter::highlightSourceCode: Out of range error: {}", e.what());
m_wasInterrupted = true;

View File

@ -45,6 +45,7 @@
#include <fonts/fonts.hpp>
#include <hex/api/events/requests_gui.hpp>
#include <hex/helpers/menu_items.hpp>
#include <hex/helpers/logger.hpp>
namespace hex::plugin::builtin {
@ -70,6 +71,16 @@ namespace hex::plugin::builtin {
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));
if (ImGui::BeginListBox("##patterns_accept", ImVec2(400_scaled, 0))) {

View File

@ -1,5 +1,6 @@
#include <ui/text_editor.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/logger.hpp>
#include <algorithm>
namespace hex::ui {
@ -50,8 +51,11 @@ namespace hex::ui {
std::smatch results;
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; };
log::warn("Syntax highlighting tokenize callback is nullptr");
return;
}
i32 linesSize = m_lines.size();
for (i32 i = 0; i < linesSize; ++i) {
auto &line = m_lines[i];
@ -74,28 +78,11 @@ namespace hex::ui {
PaletteIndex token_color = PaletteIndex::Default;
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)
current = current + 1;
else {
auto token_offset = token_begin - first.m_charsIter;
current = first + token_offset;
u64 token_length = 0;
Line::Flags flags(0);