#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include std::string g_base_address; ImFont * g_font_regular; ImFont * g_font_bold; ImFont * g_font_bold_large; struct Markdown : public imgui_md { ImFont * get_font() const override { if (m_is_table_header) { return g_font_bold; } switch (m_hlevel) { case 0: return m_is_strong ? g_font_bold : g_font_regular; case 1: return g_font_bold_large; default: return g_font_bold; } } void open_url() const override { std::array buffer; std::string command = "browse -f markdown "; std::string_view prefix(m_href.data(), 4); if (prefix == "http") command += m_href; else { prefix.remove_suffix(2); if (prefix == "//") command += "https:" + m_href; else { prefix.remove_suffix(1); if (prefix == "/") { if (g_base_address.empty()) return; // TODO: an error else command += g_base_address + m_href; } else return; // TODO: also an error } } std::unique_ptr opener(popen(command.c_str(), "r"), pclose); if (!opener) return; // TODO: time to do some error handling while (nullptr != fgets(buffer.data(), buffer.size(), opener.get())) { // TODO: Support reopening } } }; static void glfw_error_callback(int error, const char * description) { std::cerr << "glfw (" << error << "): " << description << std::endl; } static void markdown(const char * str, const char * str_end) { static Markdown s_printer; s_printer.print(str, str_end); } ImVec2 g_window_size; static void resized(GLFWwindow *, int width, int height) { g_window_size.x = static_cast(width); g_window_size.y = static_cast(height); } static void print_usage(const char * program) { std::cerr << "Usage: " << program << " [-b BASE_ADDRESS] FILE" << std::endl; } int main(int argc, char ** argv) { int opt; while (-1 != (opt = getopt(argc, argv, "b:"))) { switch (opt) { case 'b': g_base_address = optarg; break; case '?': default: print_usage(argv[0]); return 2; } } if (optind >= argc) { print_usage(argv[0]); return 2; } glfwSetErrorCallback(glfw_error_callback); if (!glfwInit()) return 1; const char * glsl_version = "#version 130"; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); GLFWwindow * window = glfwCreateWindow(1280, 720, "Markdown", nullptr, nullptr); if (nullptr == window) return 1; glfwMakeContextCurrent(window); glfwSwapInterval(1); glfwSetWindowSizeCallback(window, resized); if (GLEW_OK != glewInit()) return 1; IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImGuiIO & io = ImGui::GetIO(); io.IniFilename = nullptr; io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; g_font_regular = io.Fonts->AddFontFromFileTTF("OpenSans-Regular.ttf", 18); g_font_bold = io.Fonts->AddFontFromFileTTF("OpenSans-Bold.ttf", 18); g_font_bold_large = io.Fonts->AddFontFromFileTTF("OpenSans-Bold.ttf", 26); ImGui::StyleColorsDark(); ImGui_ImplGlfw_InitForOpenGL(window, true); ImGui_ImplOpenGL3_Init(glsl_version); std::ifstream in; in.open(argv[optind]); std::string text(std::istreambuf_iterator(in), {}); in.close(); while (!glfwWindowShouldClose(window)) { glfwPollEvents(); ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); ImGui::SetNextWindowPos({0, 0}); ImGui::SetNextWindowSize(g_window_size); ImGui::Begin( "Markdown", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoSavedSettings ); markdown(text.data(), text.data() + text.size()); ImGui::End(); ImGui::Render(); int display_w, display_h; glfwGetFramebufferSize(window, &display_w, &display_h); glViewport(0, 0, display_w, display_h); glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); glfwSwapBuffers(window); } ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplGlfw_Shutdown(); ImGui::DestroyContext(); glfwDestroyWindow(window); glfwTerminate(); }