Compare commits

...

2 Commits

6 changed files with 143 additions and 54 deletions

View File

@ -15,7 +15,7 @@ LogEntry::LogEntry(time_t time_, std::string message_) : time(time_), message(st
}
std::string format_log(const LogEntry& entry) {
std::string to_string(const LogEntry& entry) {
struct tm tm;
char time_as_str[128] = {0};
strftime(time_as_str, 127 * sizeof(char), "%c", localtime_r(&entry.time, &tm));

2
log.h
View File

@ -12,7 +12,7 @@ struct LogEntry {
};
extern std::vector<LogEntry> log_entries;
std::string format_log(const LogEntry& entry);
std::string to_string(const LogEntry& entry);
void print_log(const LogEntry& entry);
void log(LogEntry entry, bool print = true);
void log(std::string entry);

View File

@ -9,7 +9,68 @@
static const Pcre2Regex LogcatEntryRegex("^\\s*(\\d+)(?:\\.\\d+)?(?:\\s+([\\w\\d._-]+))?\\s+(\\d+)\\s+(\\d+)\\s+([A-Z])\\s+(.+?)\\s*:\\s(.*)$");
static const Pcre2Regex BufferRegex("^--------- (?:beginning of|switch to) (\\w+)$");
Priority priority_from(char c) {
const char* to_string(Priority priority) {
switch (priority) {
case Priority::Verbose: return "Verbose";
case Priority::Debug: return "Debug";
case Priority::Info: return "Info";
case Priority::Warn: return "Warning";
case Priority::Error: return "Error";
case Priority::Fatal: return "Fatal";
case Priority::Unknown: return "Unknown";
}
}
const char* to_string(Buffer buffer) {
switch (buffer) {
case Buffer::Main: return "Main";
case Buffer::System: return "System";
case Buffer::Radio: return "Radio";
case Buffer::Events: return "Events";
case Buffer::Crash: return "Crash";
case Buffer::Unknown: return "Unknown";
}
}
static std::string leftpad(const std::string& str, size_t characters) {
return str.size() >= characters
? str
: std::string(characters - str.size(), ' ') + str;
}
static inline char to_char(Priority priority) {
switch (priority) {
case Priority::Verbose: return 'V';
case Priority::Debug: return 'D';
case Priority::Info: return 'I';
case Priority::Warn: return 'W';
case Priority::Error: return 'E';
case Priority::Fatal: return 'F';
case Priority::Unknown: return 'U';
}
}
static inline std::string rightpad(const std::string& str, size_t characters) {
return str.size() >= characters
? str
: str + std::string(characters - str.size(), ' ');
}
std::string to_string(const LogcatEntry& logcat_entry) {
char logcat_style_time_as_str[32] = {0};
struct tm tm;
strftime(logcat_style_time_as_str, 31 * sizeof(char), "%Y-%m-%d %H:%M:%S", localtime_r(&logcat_entry.time, &tm));
return std::string(logcat_style_time_as_str)
+ ' ' + leftpad(logcat_entry.user.value_or(" "), 5)
+ ' ' + leftpad(std::to_string(logcat_entry.pid), 5)
+ ' ' + leftpad(std::to_string(logcat_entry.tid), 5)
+ ' ' + to_char(logcat_entry.priority)
+ ' ' + rightpad(logcat_entry.tag, 5)
+ ": " + logcat_entry.message;
}
static inline Priority priority_from(char c) {
switch (c) {
case 'V': return Priority::Verbose;
case 'D': return Priority::Debug;
@ -21,29 +82,6 @@ Priority priority_from(char c) {
}
}
const char* priority_to(Priority priority) {
switch (priority) {
case Priority::Verbose: return "Verbose";
case Priority::Debug: return "Debug";
case Priority::Info: return "Info";
case Priority::Warn: return "Warning";
case Priority::Error: return "Error";
case Priority::Fatal: return "Fatal";
default: return "Unknown";
}
}
const char* buffer_to(Buffer buffer) {
switch (buffer) {
case Buffer::Main: return "Main";
case Buffer::System: return "System";
case Buffer::Radio: return "Radio";
case Buffer::Events: return "Events";
case Buffer::Crash: return "Crash";
default: return "Unknown";
}
}
static inline long to_long(const char* str, const char* expected_end) {
char* endptr;

View File

@ -34,9 +34,9 @@ struct LogcatEntry {
std::string message;
};
Priority priority_from(char c);
const char* priority_to(Priority priority);
const char* buffer_to(Buffer buffer);
const char* to_string(Priority priority);
const char* to_string(Buffer buffer);
std::string to_string(const LogcatEntry& logcat_entry);
std::optional<LogcatEntry> try_parse_logcat_entry(char* buf, size_t length, Buffer buffer);
std::optional<Buffer> try_parse_buffer(char* buf, size_t length);

View File

@ -5,6 +5,32 @@
#include "../log.h"
#include "logs.h"
static inline void render_table_item(const LogEntry& log_entry, size_t log_entry_index) {
struct tm tm;
char time_as_str[128] = {0};
strftime(time_as_str, 127 * sizeof(char), "%c", localtime_r(&log_entry.time, &tm));
auto table_item_popup = [&](unsigned char index) {
// is it safe to use the index as a id? i mean, you can't access the clear button when the popup is active
std::string id = std::to_string(log_entry_index * 10 + index);
if (ImGui::BeginPopupContextItem(id.c_str())) {
ImGui::TextDisabled("[%s] %s", time_as_str, log_entry.message.c_str());
ImGui::Separator();
ImGui::PushFont(nullptr);
if (ImGui::Selectable("Copy")) ImGui::SetClipboardText(to_string(log_entry).c_str());
if (ImGui::Selectable("Copy Time")) ImGui::SetClipboardText(time_as_str);
if (ImGui::Selectable("Copy Message")) ImGui::SetClipboardText(log_entry.message.c_str());
ImGui::PopFont();
ImGui::EndPopup();
}
};
ImGui::TableNextRow();
if (ImGui::TableSetColumnIndex(0)) { ImGui::TextUnformatted(time_as_str); table_item_popup(0); }
if (ImGui::TableSetColumnIndex(1)) { ImGui::TextUnformatted(log_entry.message); table_item_popup(1); }
}
static inline void render_table(ImFont* monospace_font, bool* autoscrolling) {
ImGui::TableSetupScrollFreeze(0, 1);
ImGui::TableSetupColumn("Time", ImGuiTableColumnFlags_None);
@ -21,14 +47,7 @@ static inline void render_table(ImFont* monospace_font, bool* autoscrolling) {
assert(i_u >= 0);
size_t i = static_cast<size_t>(i_u);
const LogEntry* log_entry = &log_entries[i];
struct tm tm;
char time_as_str[128] = {0};
strftime(time_as_str, 127 * sizeof(char), "%c", localtime_r(&log_entry->time, &tm));
ImGui::TableNextRow();
if (ImGui::TableSetColumnIndex(0)) ImGui::TextUnformatted(time_as_str);
if (ImGui::TableSetColumnIndex(1)) ImGui::TextUnformatted(log_entry->message);
render_table_item(log_entries[i], i);
}
}
clipper.End();
@ -59,7 +78,7 @@ void logs_window(ImFont* monospace_font, bool* __restrict autoscrolling, bool* _
if (!text.empty()) {
text += '\n';
}
text += format_log(entry);
text += to_string(entry);
}
ImGui::SetClipboardText(text.c_str());
}

View File

@ -8,6 +8,49 @@
#include "../logcat_thread.h"
#include "main.h"
static inline void render_table_item(const LogcatEntry& logcat_entry, size_t logcat_entry_index) {
struct tm tm;
char time_as_str[128] = {0};
strftime(time_as_str, 127 * sizeof(char), "%c", localtime_r(&logcat_entry.time, &tm));
auto table_item_popup = [&](unsigned char index) {
// is it safe to use the index as a id? i mean, you can't access the clear button when the popup is active
std::string id = std::to_string(logcat_entry_index * 10 + index);
if (ImGui::BeginPopupContextItem(id.c_str())) {
std::string text = to_string(logcat_entry);
ImGui::TextDisabled("%s", text.c_str());
ImGui::Separator();
ImGui::PushFont(nullptr);
if (ImGui::Selectable("Copy")) ImGui::SetClipboardText(text.c_str());
if (ImGui::Selectable("Copy User", false, logcat_entry.user ? 0 : ImGuiSelectableFlags_Disabled)) {
ImGui::SetClipboardText(logcat_entry.user->c_str());
}
if (ImGui::Selectable("Copy PID")) ImGui::SetClipboardText(std::to_string(logcat_entry.pid).c_str());
if (ImGui::Selectable("Copy TID")) ImGui::SetClipboardText(std::to_string(logcat_entry.tid).c_str());
if (ImGui::Selectable("Copy Buffer")) ImGui::SetClipboardText(to_string(logcat_entry.buffer));
if (ImGui::Selectable("Copy Priority")) ImGui::SetClipboardText(to_string(logcat_entry.priority));
if (ImGui::Selectable("Copy Tag")) ImGui::SetClipboardText(logcat_entry.tag.c_str());
if (ImGui::Selectable("Copy Message")) ImGui::SetClipboardText(logcat_entry.message.c_str());
ImGui::PopFont();
ImGui::EndPopup();
}
};
ImGui::TableNextRow();
if (ImGui::TableSetColumnIndex(0)) { ImGui::TextUnformatted(time_as_str); table_item_popup(0); }
if (logcat_entry.user && ImGui::TableSetColumnIndex(1)) {
ImGui::TextUnformatted(*logcat_entry.user);
table_item_popup(1);
}
if (ImGui::TableSetColumnIndex(2)) { ImGui::Text("%zu", logcat_entry.pid); table_item_popup(2); }
if (ImGui::TableSetColumnIndex(3)) { ImGui::Text("%zu", logcat_entry.tid); table_item_popup(3); }
if (ImGui::TableSetColumnIndex(4)) { ImGui::TextUnformatted(to_string(logcat_entry.buffer)); table_item_popup(4); }
if (ImGui::TableSetColumnIndex(5)) { ImGui::TextUnformatted(to_string(logcat_entry.priority)); table_item_popup(5); }
if (ImGui::TableSetColumnIndex(6)) { ImGui::TextUnformatted(logcat_entry.tag); table_item_popup(6); }
if (ImGui::TableSetColumnIndex(7)) { ImGui::TextUnformatted(logcat_entry.message); table_item_popup(7); }
}
static inline void render_table(ImFont* monospace_font, std::vector<LogcatEntry>& logcat_entries, std::vector<size_t>& filtered_logcat_entry_offsets) {
ImGui::TableSetupScrollFreeze(0, 1);
ImGui::TableSetupColumn("Time", ImGuiTableColumnFlags_None);
@ -25,23 +68,12 @@ static inline void render_table(ImFont* monospace_font, std::vector<LogcatEntry>
ImGuiListClipper clipper;
clipper.Begin(static_cast<int>(filtered_logcat_entry_offsets.size()));
while (clipper.Step()) {
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) {
const LogcatEntry* logcat_entry = &logcat_entries[filtered_logcat_entry_offsets[static_cast<size_t>(i)]];
struct tm tm;
char time_as_str[128] = {0};
strftime(time_as_str, 127 * sizeof(char), "%c", localtime_r(&logcat_entry->time, &tm));
for (int i_u = clipper.DisplayStart; i_u < clipper.DisplayEnd; i_u++) {
assert(i_u >= 0);
size_t i = static_cast<size_t>(i_u);
ImGui::TableNextRow();
if (ImGui::TableSetColumnIndex(0)) ImGui::TextUnformatted(time_as_str);
if (logcat_entry->user && ImGui::TableSetColumnIndex(1)) {
ImGui::TextUnformatted(*logcat_entry->user);
}
if (ImGui::TableSetColumnIndex(2)) ImGui::Text("%zu", logcat_entry->pid);
if (ImGui::TableSetColumnIndex(3)) ImGui::Text("%zu", logcat_entry->tid);
if (ImGui::TableSetColumnIndex(4)) ImGui::TextUnformatted(buffer_to(logcat_entry->buffer));
if (ImGui::TableSetColumnIndex(5)) ImGui::TextUnformatted(priority_to(logcat_entry->priority));
if (ImGui::TableSetColumnIndex(6)) ImGui::TextUnformatted(logcat_entry->tag);
if (ImGui::TableSetColumnIndex(7)) ImGui::TextUnformatted(logcat_entry->message);
size_t logcat_entry_index = filtered_logcat_entry_offsets[i];
render_table_item(logcat_entries[logcat_entry_index], logcat_entry_index);
}
}
clipper.End();