ux: Reduce file loading time to basically zero
This commit is contained in:
parent
b11dbe4fe1
commit
7b61268f22
@ -19,7 +19,7 @@ namespace hex {
|
||||
class Task {
|
||||
public:
|
||||
Task() = default;
|
||||
Task(std::string unlocalizedName, u64 maxValue, std::function<void(Task &)> function);
|
||||
Task(std::string unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function);
|
||||
|
||||
Task(const Task&) = delete;
|
||||
Task(Task &&other) noexcept;
|
||||
@ -28,6 +28,7 @@ namespace hex {
|
||||
void update(u64 value = 0);
|
||||
void setMaxValue(u64 value);
|
||||
|
||||
[[nodiscard]] bool isBackgroundTask() const;
|
||||
[[nodiscard]] bool isFinished() const;
|
||||
[[nodiscard]] bool hadException() const;
|
||||
[[nodiscard]] bool wasInterrupted() const;
|
||||
@ -56,6 +57,7 @@ namespace hex {
|
||||
std::function<void()> m_interruptCallback;
|
||||
|
||||
bool m_shouldInterrupt = false;
|
||||
bool m_background = true;
|
||||
|
||||
bool m_interrupted = false;
|
||||
bool m_finished = false;
|
||||
@ -89,6 +91,7 @@ namespace hex {
|
||||
constexpr static auto NoProgress = 0;
|
||||
|
||||
static TaskHolder createTask(std::string name, u64 maxValue, std::function<void(Task &)> function);
|
||||
static TaskHolder createBackgroundTask(std::string name, std::function<void(Task &)> function);
|
||||
static void collectGarbage();
|
||||
|
||||
static size_t getRunningTaskCount();
|
||||
|
@ -9,11 +9,11 @@ namespace hex {
|
||||
|
||||
std::mutex TaskManager::s_deferredCallsMutex;
|
||||
|
||||
std::list<std::shared_ptr<Task>> TaskManager::s_tasks;
|
||||
std::list<std::shared_ptr<Task>> TaskManager::s_tasks, s_backgroundTasks;
|
||||
std::list<std::function<void()>> TaskManager::s_deferredCalls;
|
||||
|
||||
Task::Task(std::string unlocalizedName, u64 maxValue, std::function<void(Task &)> function)
|
||||
: m_unlocalizedName(std::move(unlocalizedName)), m_currValue(0), m_maxValue(maxValue) {
|
||||
Task::Task(std::string unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function)
|
||||
: m_unlocalizedName(std::move(unlocalizedName)), m_currValue(0), m_maxValue(maxValue), m_background(background) {
|
||||
this->m_thread = std::thread([this, func = std::move(function)] {
|
||||
try {
|
||||
func(*this);
|
||||
@ -83,6 +83,12 @@ namespace hex {
|
||||
this->m_interruptCallback = std::move(callback);
|
||||
}
|
||||
|
||||
bool Task::isBackgroundTask() const {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
return this->m_background;
|
||||
}
|
||||
|
||||
bool Task::isFinished() const {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
@ -164,13 +170,20 @@ namespace hex {
|
||||
|
||||
|
||||
TaskHolder TaskManager::createTask(std::string name, u64 maxValue, std::function<void(Task &)> function) {
|
||||
s_tasks.emplace_back(std::make_shared<Task>(std::move(name), maxValue, std::move(function)));
|
||||
s_tasks.emplace_back(std::make_shared<Task>(std::move(name), maxValue, false, std::move(function)));
|
||||
|
||||
return TaskHolder(s_tasks.back());
|
||||
}
|
||||
|
||||
TaskHolder TaskManager::createBackgroundTask(std::string name, std::function<void(Task &)> function) {
|
||||
s_backgroundTasks.emplace_back(std::make_shared<Task>(std::move(name), 0, true, std::move(function)));
|
||||
|
||||
return TaskHolder(s_backgroundTasks.back());
|
||||
}
|
||||
|
||||
void TaskManager::collectGarbage() {
|
||||
std::erase_if(s_tasks, [](const auto &task) { return task->isFinished() && !task->hadException(); });
|
||||
std::erase_if(s_backgroundTasks, [](const auto &task) { return task->isFinished(); });
|
||||
}
|
||||
|
||||
std::list<std::shared_ptr<Task>> &TaskManager::getRunningTasks() {
|
||||
|
@ -52,6 +52,7 @@ namespace hex {
|
||||
|
||||
ImGui::Texture m_logoTexture = { nullptr };
|
||||
|
||||
std::mutex m_popupMutex;
|
||||
std::list<std::string> m_popupsToOpen;
|
||||
std::vector<int> m_pressedKeys;
|
||||
|
||||
|
@ -144,6 +144,8 @@ namespace hex {
|
||||
});
|
||||
|
||||
EventManager::subscribe<RequestOpenPopup>(this, [this](auto name) {
|
||||
std::scoped_lock lock(this->m_popupMutex);
|
||||
|
||||
this->m_popupsToOpen.push_back(name);
|
||||
});
|
||||
|
||||
@ -424,15 +426,17 @@ namespace hex {
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
{
|
||||
std::scoped_lock lock(this->m_popupMutex);
|
||||
this->m_popupsToOpen.remove_if([](const auto &name) {
|
||||
if (ImGui::IsPopupOpen(name.c_str()))
|
||||
return true;
|
||||
else
|
||||
ImGui::OpenPopup(name.c_str());
|
||||
|
||||
this->m_popupsToOpen.remove_if([](const auto &name) {
|
||||
if (ImGui::IsPopupOpen(name.c_str()))
|
||||
return true;
|
||||
else
|
||||
ImGui::OpenPopup(name.c_str());
|
||||
|
||||
return false;
|
||||
});
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
TaskManager::runDeferredCalls();
|
||||
|
||||
|
@ -106,19 +106,22 @@ namespace hex::plugin::builtin {
|
||||
|
||||
void ViewPatternData::drawContent() {
|
||||
if (ImGui::Begin(View::toWindowName("hex.builtin.view.pattern_data.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
if (ImHexApi::Provider::isValid() && provider->isReadable() && !ProviderExtraData::get(provider).patternLanguage.runtime->isRunning()) {
|
||||
if (ImHexApi::Provider::isValid()) {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
auto &runtime = ProviderExtraData::get(provider).patternLanguage.runtime;
|
||||
|
||||
auto &sortedPatterns = this->m_sortedPatterns[ImHexApi::Provider::get()];
|
||||
if (beginPatternTable(provider, ProviderExtraData::get(provider).patternLanguage.runtime->getAllPatterns(), sortedPatterns)) {
|
||||
ImGui::TableHeadersRow();
|
||||
if (!sortedPatterns.empty()) {
|
||||
if (provider->isReadable() && runtime != nullptr && !runtime->isRunning()) {
|
||||
auto &sortedPatterns = this->m_sortedPatterns[ImHexApi::Provider::get()];
|
||||
if (beginPatternTable(provider, ProviderExtraData::get(provider).patternLanguage.runtime->getAllPatterns(), sortedPatterns)) {
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
for (auto &patterns : sortedPatterns)
|
||||
patterns->accept(this->m_patternDrawer);
|
||||
if (!sortedPatterns.empty()) {
|
||||
for (auto &patterns : sortedPatterns)
|
||||
patterns->accept(this->m_patternDrawer);
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -114,58 +114,60 @@ namespace hex::plugin::builtin {
|
||||
patternLanguageData.runtime = std::make_unique<pl::PatternLanguage>();
|
||||
ContentRegistry::PatternLanguage::configureRuntime(*patternLanguageData.runtime, provider);
|
||||
|
||||
if (!this->m_autoLoadPatterns)
|
||||
return;
|
||||
TaskManager::createBackgroundTask("Analyzing file content", [this, provider, &data = patternLanguageData](auto &) {
|
||||
if (!this->m_autoLoadPatterns)
|
||||
return;
|
||||
|
||||
// Copy over current pattern source code to the new provider
|
||||
if (!this->m_syncPatternSourceCode) {
|
||||
patternLanguageData.sourceCode = this->m_textEditor.GetText();
|
||||
}
|
||||
|
||||
auto &runtime = patternLanguageData.runtime;
|
||||
|
||||
auto mimeType = magic::getMIMEType(provider);
|
||||
|
||||
bool foundCorrectType = false;
|
||||
runtime->addPragma("MIME", [&mimeType, &foundCorrectType](pl::PatternLanguage &runtime, const std::string &value) {
|
||||
hex::unused(runtime);
|
||||
|
||||
if (value == mimeType) {
|
||||
foundCorrectType = true;
|
||||
return true;
|
||||
// Copy over current pattern source code to the new provider
|
||||
if (!this->m_syncPatternSourceCode) {
|
||||
data.sourceCode = this->m_textEditor.GetText();
|
||||
}
|
||||
|
||||
auto &runtime = data.runtime;
|
||||
|
||||
auto mimeType = magic::getMIMEType(provider);
|
||||
|
||||
bool foundCorrectType = false;
|
||||
runtime->addPragma("MIME", [&mimeType, &foundCorrectType](pl::PatternLanguage &runtime, const std::string &value) {
|
||||
hex::unused(runtime);
|
||||
|
||||
if (value == mimeType) {
|
||||
foundCorrectType = true;
|
||||
return true;
|
||||
}
|
||||
return !std::all_of(value.begin(), value.end(), isspace) && !value.ends_with('\n') && !value.ends_with('\r');
|
||||
});
|
||||
|
||||
this->m_possiblePatternFiles.clear();
|
||||
|
||||
std::error_code errorCode;
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Patterns)) {
|
||||
for (auto &entry : std::fs::recursive_directory_iterator(dir, errorCode)) {
|
||||
foundCorrectType = false;
|
||||
if (!entry.is_regular_file())
|
||||
continue;
|
||||
|
||||
fs::File file(entry.path(), fs::File::Mode::Read);
|
||||
if (!file.isValid())
|
||||
continue;
|
||||
|
||||
runtime->getInternals().preprocessor->preprocess(*runtime, file.readString());
|
||||
|
||||
if (foundCorrectType)
|
||||
this->m_possiblePatternFiles.push_back(entry.path());
|
||||
|
||||
runtime->reset();
|
||||
}
|
||||
}
|
||||
|
||||
runtime->addPragma("MIME", [](pl::PatternLanguage&, const std::string &value) { return !value.empty(); });
|
||||
|
||||
if (!this->m_possiblePatternFiles.empty()) {
|
||||
this->m_selectedPatternFile = 0;
|
||||
EventManager::post<RequestOpenPopup>("hex.builtin.view.pattern_editor.accept_pattern"_lang);
|
||||
this->m_acceptPatternWindowOpen = true;
|
||||
}
|
||||
return !std::all_of(value.begin(), value.end(), isspace) && !value.ends_with('\n') && !value.ends_with('\r');
|
||||
});
|
||||
|
||||
this->m_possiblePatternFiles.clear();
|
||||
|
||||
std::error_code errorCode;
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Patterns)) {
|
||||
for (auto &entry : std::fs::recursive_directory_iterator(dir, errorCode)) {
|
||||
foundCorrectType = false;
|
||||
if (!entry.is_regular_file())
|
||||
continue;
|
||||
|
||||
fs::File file(entry.path(), fs::File::Mode::Read);
|
||||
if (!file.isValid())
|
||||
continue;
|
||||
|
||||
runtime->getInternals().preprocessor->preprocess(*runtime, file.readString());
|
||||
|
||||
if (foundCorrectType)
|
||||
this->m_possiblePatternFiles.push_back(entry.path());
|
||||
|
||||
runtime->reset();
|
||||
}
|
||||
}
|
||||
|
||||
runtime->addPragma("MIME", [](pl::PatternLanguage&, const std::string &value) { return !value.empty(); });
|
||||
|
||||
if (!this->m_possiblePatternFiles.empty()) {
|
||||
this->m_selectedPatternFile = 0;
|
||||
EventManager::post<RequestOpenPopup>("hex.builtin.view.pattern_editor.accept_pattern"_lang);
|
||||
this->m_acceptPatternWindowOpen = true;
|
||||
}
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProviderChanged>(this, [this](prv::Provider *oldProvider, prv::Provider *newProvider) {
|
||||
|
@ -52,40 +52,49 @@ namespace hex::plugin::builtin {
|
||||
|
||||
};
|
||||
|
||||
static std::atomic<bool> s_recentProvidersUpdating = false;
|
||||
static std::list<RecentProvider> s_recentProviders;
|
||||
|
||||
static void updateRecentProviders() {
|
||||
s_recentProviders.clear();
|
||||
TaskManager::createBackgroundTask("Updating recent files", [](auto&){
|
||||
if (s_recentProvidersUpdating)
|
||||
return;
|
||||
|
||||
// Query all recent providers
|
||||
std::vector<std::fs::path> recentFilePaths;
|
||||
for (const auto &folder : fs::getDefaultPaths(fs::ImHexPath::Recent)) {
|
||||
for (const auto &entry : std::fs::directory_iterator(folder)) {
|
||||
if (entry.is_regular_file())
|
||||
recentFilePaths.push_back(entry.path());
|
||||
s_recentProvidersUpdating = true;
|
||||
ON_SCOPE_EXIT { s_recentProvidersUpdating = false; };
|
||||
|
||||
s_recentProviders.clear();
|
||||
|
||||
// Query all recent providers
|
||||
std::vector<std::fs::path> recentFilePaths;
|
||||
for (const auto &folder : fs::getDefaultPaths(fs::ImHexPath::Recent)) {
|
||||
for (const auto &entry : std::fs::directory_iterator(folder)) {
|
||||
if (entry.is_regular_file())
|
||||
recentFilePaths.push_back(entry.path());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort recent provider files by last modified time
|
||||
std::sort(recentFilePaths.begin(), recentFilePaths.end(), [](const auto &a, const auto &b) {
|
||||
return std::fs::last_write_time(a) > std::fs::last_write_time(b);
|
||||
// Sort recent provider files by last modified time
|
||||
std::sort(recentFilePaths.begin(), recentFilePaths.end(), [](const auto &a, const auto &b) {
|
||||
return std::fs::last_write_time(a) > std::fs::last_write_time(b);
|
||||
});
|
||||
|
||||
std::unordered_set<RecentProvider, RecentProvider::HashFunction> uniqueProviders;
|
||||
for (u32 i = 0; i < recentFilePaths.size() && uniqueProviders.size() < 5; i++) {
|
||||
auto &path = recentFilePaths[i];
|
||||
try {
|
||||
auto jsonData = nlohmann::json::parse(fs::File(path, fs::File::Mode::Read).readString());
|
||||
uniqueProviders.insert(RecentProvider {
|
||||
.displayName = jsonData["displayName"],
|
||||
.type = jsonData["type"],
|
||||
.filePath = path,
|
||||
.data = jsonData
|
||||
});
|
||||
} catch (...) { }
|
||||
}
|
||||
|
||||
std::copy(uniqueProviders.begin(), uniqueProviders.end(), std::front_inserter(s_recentProviders));
|
||||
});
|
||||
|
||||
std::unordered_set<RecentProvider, RecentProvider::HashFunction> uniqueProviders;
|
||||
for (u32 i = 0; i < recentFilePaths.size() && uniqueProviders.size() < 5; i++) {
|
||||
auto &path = recentFilePaths[i];
|
||||
try {
|
||||
auto jsonData = nlohmann::json::parse(fs::File(path, fs::File::Mode::Read).readString());
|
||||
uniqueProviders.insert(RecentProvider {
|
||||
.displayName = jsonData["displayName"],
|
||||
.type = jsonData["type"],
|
||||
.filePath = path,
|
||||
.data = jsonData
|
||||
});
|
||||
} catch (...) { }
|
||||
}
|
||||
|
||||
std::copy(uniqueProviders.begin(), uniqueProviders.end(), std::front_inserter(s_recentProviders));
|
||||
}
|
||||
|
||||
static void loadRecentProvider(const RecentProvider &recentProvider) {
|
||||
@ -227,13 +236,15 @@ namespace hex::plugin::builtin {
|
||||
ImGui::UnderlinedText("hex.builtin.welcome.start.recent"_lang);
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5_scaled);
|
||||
{
|
||||
for (const auto &recentProvider : s_recentProviders) {
|
||||
ImGui::PushID(&recentProvider);
|
||||
ON_SCOPE_EXIT { ImGui::PopID(); };
|
||||
if (!s_recentProvidersUpdating) {
|
||||
for (const auto &recentProvider : s_recentProviders) {
|
||||
ImGui::PushID(&recentProvider);
|
||||
ON_SCOPE_EXIT { ImGui::PopID(); };
|
||||
|
||||
if (ImGui::BulletHyperlink(recentProvider.displayName.c_str())) {
|
||||
loadRecentProvider(recentProvider);
|
||||
break;
|
||||
if (ImGui::BulletHyperlink(recentProvider.displayName.c_str())) {
|
||||
loadRecentProvider(recentProvider);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -500,7 +511,7 @@ namespace hex::plugin::builtin {
|
||||
});
|
||||
|
||||
ContentRegistry::Interface::addMenuItem("hex.builtin.menu.file", 1075, [&] {
|
||||
if (ImGui::BeginMenu("hex.builtin.menu.file.open_recent"_lang, !s_recentProviders.empty())) {
|
||||
if (ImGui::BeginMenu("hex.builtin.menu.file.open_recent"_lang, !s_recentProvidersUpdating && !s_recentProviders.empty())) {
|
||||
// Copy to avoid changing list while iteration
|
||||
auto recentProviders = s_recentProviders;
|
||||
for (auto &recentProvider : recentProviders) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user