add some features in Unvirt

- add style [simple | full] command to allow simple display. current object list display take too much space.
- add search [obj | mgr] [plain | re] <text> command to allow user search object or manager list by substring or regex.
- add ls search <page> to browse the search result.
- set IronPad minidump dump type from full memory to normal.
- fix Unvirt ls command page count display error.
This commit is contained in:
2023-10-28 18:17:53 +08:00
parent e4a67a50a5
commit c7af11702f
5 changed files with 349 additions and 67 deletions

View File

@ -1,6 +1,7 @@
#include "UnvirtContext.hpp"
#include <CK2/MgrImpls/CKPathManager.hpp>
#include <cstdarg>
#include <regex>
namespace Unvirt::Context {
@ -8,7 +9,8 @@ namespace Unvirt::Context {
UnvirtContext::UnvirtContext() :
m_Root(), m_Splitter(), m_Help(nullptr),
m_PageLen(10u), m_OrderExit(false),
m_PageLen(10u), m_ListStyleIsFull(true), m_OrderExit(false),
m_SearchPart(SearchPart::None), m_SearchIdxResult(),
m_Ctx(nullptr), m_FileReader(nullptr), m_IsShallowRead(true) {
// create command root
@ -49,7 +51,7 @@ namespace Unvirt::Context {
)
)
->Then((new CmdHelper::Literal("ls"))
->Then((new CmdHelper::Choice("part", { "obj", "mgr"}))
->Then((new CmdHelper::Choice("part", { "obj", "mgr", "search"}))
->Comment("Which list you want to list.")
->Then((new CmdHelper::IntArgument("page", [](int32_t v) -> bool { return v > 0; }))
->Comment("The page index. Start with 1.")
@ -84,6 +86,21 @@ namespace Unvirt::Context {
)
)
)
->Then((new CmdHelper::Literal("search"))
->Then((new CmdHelper::Choice("part", { "obj", "mgr"}))
->Comment("Which list you want to search.")
->Then((new CmdHelper::Choice("mode", { "plain", "re"}))
->Comment("The search mode. `plain` will search by substring and `re` will do regex search.")
->Then((new CmdHelper::StringArgument("text"))
->Comment("The text or regex to search.")
->Executes(
std::bind(&UnvirtContext::ProcSearch, this, std::placeholders::_1),
"Search object or manager by text or regex. Please note that the regex have limited UTF8 support and may cause undefined behavior."
)
)
)
)
)
->Then((new CmdHelper::Literal("items"))
->Then((new CmdHelper::IntArgument("count", [](int32_t v) -> bool { return v > 0; }))
->Comment("The count of items you want to show in one page.")
@ -93,6 +110,15 @@ namespace Unvirt::Context {
)
)
)
->Then((new CmdHelper::Literal("style"))
->Then((new CmdHelper::Choice("level", { "full", "simple"}))
->Comment("The amount of showen content.")
->Executes(
std::bind(&UnvirtContext::ProcStyle, this, std::placeholders::_1),
"Change the detail level of showen data in `ls` command."
)
)
)
->Then((new CmdHelper::Literal("encoding"))
->Then((new CmdHelper::EncodingArgument("enc"))
->Comment("CKContext used encoding splitted by ','. Support mutiple encoding.")
@ -173,6 +199,9 @@ namespace Unvirt::Context {
void UnvirtContext::ClearDocument() {
if (m_FileReader == nullptr) return;
// clear search result
m_SearchPart = SearchPart::None;
m_SearchIdxResult.clear();
// delete reader
delete m_FileReader;
m_FileReader = nullptr;
@ -186,6 +215,14 @@ namespace Unvirt::Context {
fprintf(stdout, UNVIRT_TERMCOL_LIGHT_YELLOW(("[CKContext] ")) "%s\n", msg);
}
}
void UnvirtContext::PrintCommonInfo(const char* u8_fmt, ...) {
va_list argptr;
va_start(argptr, u8_fmt);
std::vfprintf(stdout, u8_fmt, argptr);
va_end(argptr);
std::fputc('\n', stdout);
}
void UnvirtContext::PrintCommonError(const char* u8_fmt, ...) {
va_list argptr;
@ -321,7 +358,7 @@ namespace Unvirt::Context {
return;
}
// get page
// get 0 based page (-1)
size_t page = *amap->Get<CmdHelper::IntArgument::vType>("page") - 1;
// show list
@ -329,21 +366,55 @@ namespace Unvirt::Context {
case 0:
{
// obj list
if (page * m_PageLen >= m_FileReader->GetFileObjects().size()) {
PrintCommonError("Page out of range.");
return;
}
Unvirt::StructFormatter::PrintObjectList(m_FileReader->GetFileObjects(), m_FileReader->GetFileInfo(), page, this->m_PageLen);
Unvirt::StructFormatter::PrintObjectList(
m_FileReader->GetFileObjects(),
m_FileReader->GetFileInfo(),
page, this->m_PageLen,
m_ListStyleIsFull
);
break;
}
case 1:
{
// mgr list
if (page * m_PageLen >= m_FileReader->GetManagersData().size()) {
PrintCommonError("Page out of range.");
return;
Unvirt::StructFormatter::PrintManagerList(
m_FileReader->GetManagersData(),
page, this->m_PageLen,
m_ListStyleIsFull
);
break;
}
case 2:
{
// search list
switch (m_SearchPart) {
case SearchPart::None:
{
PrintCommonError("No search result to list.");
break;
}
case SearchPart::Object:
{
Unvirt::StructFormatter::PrintSearchedObjectList(
m_SearchIdxResult,
m_FileReader->GetFileObjects(),
m_FileReader->GetFileInfo(),
page, this->m_PageLen,
m_ListStyleIsFull
);
break;
}
case SearchPart::Manager:
{
Unvirt::StructFormatter::PrintSearchedManagerList(
m_SearchIdxResult,
m_FileReader->GetManagersData(),
page, this->m_PageLen,
m_ListStyleIsFull
);
break;
}
}
Unvirt::StructFormatter::PrintManagerList(m_FileReader->GetManagersData(), page, this->m_PageLen);
break;
}
}
@ -376,7 +447,8 @@ namespace Unvirt::Context {
PrintCommonError("Index out of range.");
return;
}
PrintCommonError("WIP function.");
// todo: finish manager display
PrintCommonError("Not supported now.");
//Unvirt::StructFormatter::PrintCKBaseManager(m_FileReader->GetManagersData()[index].Data);
break;
}
@ -416,11 +488,110 @@ namespace Unvirt::Context {
}
}
void UnvirtContext::ProcSearch(const CmdHelper::ArgumentsMap* amap) {
// check pre-requirement
if (!HasOpenedFile()) {
PrintCommonError("No loaded file.");
return;
}
// get search text
std::string search_text(*amap->Get<CmdHelper::StringArgument::vType>("text"));
// analyse search mode
std::function<bool(const LibCmo::XContainer::XString&)> search_fct = [](const LibCmo::XContainer::XString&) -> bool { return false; };
switch (*amap->Get<CmdHelper::Choice::vType>("mode")) {
case 0:
{
// plain mode
search_fct = [&search_text](const LibCmo::XContainer::XString& cmp) -> bool {
return cmp.find(search_text) != std::string::npos;
};
break;
}
case 1:
{
// regex mode
// try construct regex
std::regex re;
try {
re = std::regex(search_text, std::regex_constants::ECMAScript);
} catch (const std::regex_error& e) {
PrintCommonError("Invalid regular expressions: %s", e.what());
return;
}
// use copy ctor capture to input regex
// because re will be freed when exiting this switch.
search_fct = [re](const LibCmo::XContainer::XString& cmp) -> bool {
return std::regex_search(cmp, re);
};
break;
}
}
// start search
switch (*amap->Get<CmdHelper::Choice::vType>("part")) {
case 0:
{
// object
m_SearchPart = SearchPart::Object;
m_SearchIdxResult.clear();
size_t counter = 0;
for (const auto& obj : m_FileReader->GetFileObjects()) {
if (search_fct(obj.Name)) {
m_SearchIdxResult.emplace_back(counter);
}
++counter;
}
break;
}
case 1:
{
// manager
m_SearchPart = SearchPart::Manager;
m_SearchIdxResult.clear();
PrintCommonError("Not supported now.");
// todo: remove this return when fixing manager searching.
return;
break;
}
}
// report search result
if (m_SearchIdxResult.empty()) {
PrintCommonInfo("Search done, but no result.");
} else {
PrintCommonInfo("Search done with %" PRIuSIZET " results. Use `ls search` to check them.", m_SearchIdxResult.size());
}
}
void UnvirtContext::ProcItems(const CmdHelper::ArgumentsMap* amap) {
// assign
m_PageLen = *amap->Get<CmdHelper::IntArgument::vType>("count");
}
void UnvirtContext::ProcStyle(const CmdHelper::ArgumentsMap* amap) {
// set list style level
switch (*amap->Get<CmdHelper::Choice::vType>("level")) {
case 0:
{
// full level
m_ListStyleIsFull = true;
break;
}
case 1:
{
// simple level
m_ListStyleIsFull = false;
break;
}
}
}
void UnvirtContext::ProcEncoding(const CmdHelper::ArgumentsMap* amap) {
const auto& encodings = *amap->Get<CmdHelper::EncodingArgument::vType>("enc");
m_Ctx->SetEncoding(encodings);