#include #include #include #include "../file.h" #include "../logcat_entry.h" static inline void import_logcat_entries(LogcatEntries& logcat_entries, bool ignore_buffer_lines, File& file); static inline void import_logcat_entries_from_clipboard(LogcatEntries& logcat_entries, bool ignore_buffer_lines); static void import_logcat_entries(LogcatEntries& logcat_entries, bool ignore_buffer_lines, auto cb); static inline std::optional open_file_picker(); void import_fragment(LogcatEntries& logcat_entries) { static bool ignore_buffer_lines = false; ImGui::Checkbox("Ignore buffer lines", &ignore_buffer_lines); if (ImGui::Button("Import from File")) { std::optional file = open_file_picker(); if (file) { ImGui::CloseCurrentPopup(); try { import_logcat_entries(logcat_entries, ignore_buffer_lines, *file); } catch (const std::exception& e) { log(std::string("Failed to import logcat entries: ") + e.what()); } } } ImGui::SameLine(); if (ImGui::Button("Import from Clipboard")) { ImGui::CloseCurrentPopup(); try { import_logcat_entries_from_clipboard(logcat_entries, ignore_buffer_lines); } catch (const std::exception& e) { log(std::string("Failed to import logcat entries: ") + e.what()); } } } static inline void import_logcat_entries(LogcatEntries& logcat_entries, bool ignore_buffer_lines, File& file) { auto handle_valid_char = [](char line[MAX_LOGCAT_LINE_SIZE], size_t* line_length, char c) -> std::optional { if (c == '\n') { return true; } if (*line_length == MAX_LOGCAT_LINE_SIZE) { throw std::runtime_error("Received line longer than 512k"); } line[*line_length] = c; (*line_length)++; return std::nullopt; }; auto handle_char = [&](char line[MAX_LOGCAT_LINE_SIZE], size_t* line_length, int c) -> std::optional { if (c != EOF) { return handle_valid_char(line, line_length, static_cast(c)); } if (feof(file.get())) { return *line_length != 0; } else if (ferror(file.get())) { throw_system_error("fread()"); } else { throw std::runtime_error("fgetc() returned EOF without setting anything"); } return std::nullopt; }; import_logcat_entries(logcat_entries, ignore_buffer_lines, [&](char line[MAX_LOGCAT_LINE_SIZE], size_t* line_length) { *line_length = 0; while (true) { int c = fgetc(file.get()); std::optional ret = handle_char(line, line_length, c); if (ret) { return *ret; } } }); } static inline void import_logcat_entries_from_clipboard(LogcatEntries& logcat_entries, bool ignore_buffer_lines) { const char* text = ImGui::GetClipboardText(); import_logcat_entries(logcat_entries, ignore_buffer_lines, [&](char line[MAX_LOGCAT_LINE_SIZE], size_t* line_length) { if (!text) { return false; } const char* newline_offset = strchr(text, '\n'); *line_length = newline_offset ? static_cast(newline_offset - text) : strlen(text); if (*line_length > MAX_LOGCAT_LINE_SIZE) { throw std::runtime_error("Received line longer than 512k"); } memcpy(line, text, *line_length); text = newline_offset ? &newline_offset[1] : nullptr; return true; }); } static void import_logcat_entries(LogcatEntries& logcat_entries, bool ignore_buffer_lines, auto cb) { char line[MAX_LOGCAT_LINE_SIZE]; size_t line_length; Buffer buffer = Buffer::Unknown; while (cb(line, &line_length)) { if (line_length == 0) { continue; } std::optional logcat_entry = try_parse_logcat_entry(line, line_length, buffer); if (logcat_entry) { logcat_entries.push_back(std::move(*logcat_entry)); continue; } std::optional new_buffer = try_parse_buffer(line, line_length); if (new_buffer) { if (!ignore_buffer_lines) { buffer = *new_buffer; } continue; } throw std::invalid_argument(std::string("Cannot parse line: ") + std::string(line, line_length)); } } static inline std::optional open_file_picker() { nfdchar_t* path; nfdfilteritem_t filters[1] = {{"Log file", "log"}}; nfdresult_t res = NFD_OpenDialog(&path, filters, 1, nullptr); if (res == NFD_OKAY) { try { File file(path, "r"); NFD_FreePath(path); return std::move(file); } catch (const std::exception& e) { NFD_FreePath(path); log(std::string("Failed to open file from file picker: ") + e.what()); } } else if (res == NFD_CANCEL) { // dialog was canceled, shrug } else { // ignore error when failing to open the file picker } return std::nullopt; }