Some refactoring

master
Melroy van den Berg 2020-12-14 19:40:08 +01:00
parent 40b4856797
commit d272b0b28f
12 changed files with 218 additions and 225 deletions

View File

@ -1,7 +1,8 @@
#include "file.h" #include "file.h"
#include <cmark-gfm.h>
#include <stdexcept> #include <stdexcept>
#include <fstream>
#include <sstream>
#include <iostream> #include <iostream>
File::File() {} File::File() {}
@ -11,9 +12,14 @@ File::File() {}
* \param path File path * \param path File path
* \return AST model of markdown file (cmark_node) * \return AST model of markdown file (cmark_node)
*/ */
cmark_node * File::read(const std::string& path) std::string const File::read(const std::string& path)
{ {
return parser.parseFile(path); std::ifstream inFile;
inFile.open(path, std::ifstream::in);
std::stringstream strStream;
strStream << inFile.rdbuf();
return strStream.str();
} }
/** /**
@ -22,22 +28,9 @@ cmark_node * File::read(const std::string& path)
* \throw runtime error when something goes wrong * \throw runtime error when something goes wrong
* \return AST model of markdown file (cmark_node) * \return AST model of markdown file (cmark_node)
*/ */
cmark_node * File::fetch(const std::string& path) std::string const File::fetch(const std::string& path)
{ {
std::stringstream contents; std::stringstream contents;
network.fetchFile(path, &contents); network.fetchFile(path, &contents);
return parser.parseStream(contents); return contents.str();
}
std::string const File::getSource(cmark_node *node)
{
return parser.getSource(node);
}
/**
* Free AST cmark_node memory, to avoid memory leaks
*/
void File::free(cmark_node *node)
{
cmark_node_free(node);
} }

View File

@ -1,26 +1,22 @@
#ifndef FILE_H #ifndef FILE_H
#define FILE_H #define FILE_H
#include "md-parser.h"
#include "network.h" #include "network.h"
#include <string> #include <string>
/** /**
* \class File * \class File
* \brief Fetch markdown file from disk or IPFS network and parse to AST * \brief Fetch markdown file from disk or IPFS network
*/ */
class File class File
{ {
public: public:
File(); File();
cmark_node * read(const std::string& path); /*!< Read file from disk */ std::string const read(const std::string& path); /*!< Read file from disk */
cmark_node * fetch(const std::string& path); /*!< Fetch file from IPFS network */ std::string const fetch(const std::string& path); /*!< Fetch file from IPFS network */
std::string const getSource(cmark_node *node); /*!< Get source code from AST */
void free(cmark_node *node); /*!< Free pointer */
private: private:
Parser parser; Network network;
Network network;
}; };
#endif #endif

View File

@ -2,26 +2,49 @@
#include <cstdlib> #include <cstdlib>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <limits.h>
#include <iostream>
#include <string.h>
#ifdef LEGACY_CXX
#include <experimental/filesystem>
namespace n_fs = ::std::experimental::filesystem;
#else
#include <filesystem>
namespace n_fs = ::std::filesystem;
#endif
int IPFS::startIPFSDaemon() int IPFS::startIPFSDaemon()
{ {
// Be sure to kill any running daemons // Be sure to kill any running daemons
std::system("killall -q ipfs"); std::system("killall -q ipfs");
/// open /dev/null for writing /// open /dev/null for writing
int fd = open("/dev/null", O_WRONLY); int fd = open("/dev/null", O_WRONLY);
dup2(fd, 1); // make stdout a copy of fd (> /dev/null) dup2(fd, 1); // make stdout a copy of fd (> /dev/null)
dup2(fd, 2); // ..and same with stderr dup2(fd, 2); // ..and same with stderr
close(fd); // close fd close(fd); // close fd
// Ignore ISO C++ forbids converting a string constant to char* // stdout and stderr now write to /dev/null
// This is valid in C. // Ready to call exec to start IPFS Daemon
#pragma GCC diagnostic push std::string currentPath = n_fs::current_path().string();
#pragma GCC diagnostic ignored "-Wwrite-strings" std::string executable = currentPath.append("/../../go-ipfs/ipfs");
// stdout and stderr now write to /dev/null const char* exe = executable.c_str();
// Ready to call exec to start IPFS Daemon std::cout << "Info: Starting IPFS Daemon from: " << exe << std::endl;
constexpr char *proc[] = { "../../go-ipfs/ipfs", "daemon", "--init", "--migrate", NULL}; char *proc[] = { strdup(exe), strdup("daemon"), strdup("--init"), strdup("--migrate"), NULL};
#pragma GCC diagnostic pop return execv(exe, proc);
return execv(proc[0], proc);
} }
/*
std::string IPFS::getExecutablePath() {
char buff[PATH_MAX];
ssize_t len = ::readlink("/proc/self/exe", buff, sizeof(buff)-1);
if (len != -1) {
buff[len] = '\0';
return std::string(buff);
}
else {
return "";
}
}*/

View File

@ -1,6 +1,8 @@
#ifndef IPFS_H #ifndef IPFS_H
#define IPFS_H #define IPFS_H
#include <string>
/** /**
* \class IPFS * \class IPFS
* \brief Helper class to start/stop IPFS deamon * \brief Helper class to start/stop IPFS deamon
@ -8,6 +10,6 @@
class IPFS class IPFS
{ {
public: public:
static int startIPFSDaemon(); static int startIPFSDaemon();
}; };
#endif #endif

View File

@ -4,25 +4,25 @@
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
pid_t child_pid = fork(); pid_t child_pid = fork();
if (child_pid == 0) if (child_pid == 0)
{ {
// Run by child process // Run by child process
return IPFS::startIPFSDaemon(); return IPFS::startIPFSDaemon();
} }
else if (child_pid > 0 ) else if (child_pid > 0 )
{ {
// Parent process (child_pid is PID of child) // Parent process (child_pid is PID of child)
auto app = Gtk::Application::create(argc, argv, "org.melroy.browser"); auto app = Gtk::Application::create(argc, argv, "org.melroy.browser");
MainWindow window; MainWindow window;
int exitCode = app->run(window); int exitCode = app->run(window);
// Kill also the child // Kill also the child
kill(child_pid, SIGTERM); kill(child_pid, SIGTERM);
return exitCode; return exitCode;
} }
else // PID < 0, error else // PID < 0, error
{ {
printf("ERROR: fork failed.\n"); printf("ERROR: fork failed.\n");
} }
} }

View File

@ -2,6 +2,8 @@
#include <gtkmm/menuitem.h> #include <gtkmm/menuitem.h>
#include <gtkmm/image.h> #include <gtkmm/image.h>
#include <cmark-gfm.h>
#include "md-parser.h"
#ifdef LEGACY_CXX #ifdef LEGACY_CXX
#include <experimental/filesystem> #include <experimental/filesystem>
@ -16,7 +18,7 @@ MainWindow::MainWindow()
m_hbox_bar(Gtk::ORIENTATION_HORIZONTAL, 0), m_hbox_bar(Gtk::ORIENTATION_HORIZONTAL, 0),
requestPath(""), requestPath(""),
finalRequestPath(""), finalRequestPath(""),
currentSourceCode("") currentContent("")
{ {
set_title("DBrowser"); set_title("DBrowser");
set_default_size(1000, 800); set_default_size(1000, 800);
@ -34,10 +36,6 @@ MainWindow::MainWindow()
m_vbox.pack_start(m_menu, false, false, 0); m_vbox.pack_start(m_menu, false, false, 0);
m_sourceCodeDialog.setText("Hallo!?");
m_sourceCodeDialog.setText("123");
// Horizontal bar // Horizontal bar
auto styleBack = m_backButton.get_style_context(); auto styleBack = m_backButton.get_style_context();
styleBack->add_class("circular"); styleBack->add_class("circular");
@ -86,7 +84,7 @@ void MainWindow::go_home()
{ {
this->requestPath = ""; this->requestPath = "";
this->finalRequestPath = ""; this->finalRequestPath = "";
this->currentSourceCode = ""; this->currentContent = "";
this->m_inputField.set_text(""); this->m_inputField.set_text("");
m_renderArea.showStartPage(); m_renderArea.showStartPage();
} }
@ -99,12 +97,12 @@ void MainWindow::input_activate()
void MainWindow::doRequest(const std::string &path) void MainWindow::doRequest(const std::string &path)
{ {
currentSourceCode = ""; currentContent = "";
if (!path.empty()) { if (!path.empty()) {
requestPath = path; requestPath = path;
} }
if (requestPath.empty()) { if (requestPath.empty()) {
std::cerr << "Empty request path." << std::endl; std::cerr << "Info: Empty request path." << std::endl;
} else { } else {
// Check if CID // Check if CID
if (requestPath.rfind("ipfs://", 0) == 0) { if (requestPath.rfind("ipfs://", 0) == 0) {
@ -143,12 +141,12 @@ void MainWindow::fetchFromIPFS()
// TODO: In a seperate thread/process? // TODO: In a seperate thread/process?
// Since otherwise this may block the UI. // Since otherwise this may block the UI.
try { try {
cmark_node *fetchDoc = m_file.fetch(finalRequestPath); currentContent = m_file.fetch(finalRequestPath);
m_renderArea.processDocument(fetchDoc); cmark_node* doc = Parser::parseContent(currentContent);
currentSourceCode = m_file.getSource(fetchDoc); m_renderArea.processDocument(doc);
m_file.free(fetchDoc); cmark_node_free(doc);
} catch (const std::runtime_error &error) { } catch (const std::runtime_error &error) {
std::cerr << "IPFS Deamon is most likely down: " << error.what() << std::endl; std::cerr << "Error: IPFS Deamon is most likely down: " << error.what() << std::endl;
// Not found (or any other issue) // Not found (or any other issue)
m_renderArea.showMessage("Page not found!", "Detailed error message: " + std::string(error.what())); m_renderArea.showMessage("Page not found!", "Detailed error message: " + std::string(error.what()));
} }
@ -162,10 +160,10 @@ void MainWindow::openFromDisk()
// std::string exePath = n_fs::current_path().string(); // std::string exePath = n_fs::current_path().string();
// std::string filePath = exePath.append("/../../test.md"); // std::string filePath = exePath.append("/../../test.md");
try { try {
cmark_node *readDoc = m_file.read(finalRequestPath); currentContent = m_file.read(finalRequestPath);
m_renderArea.processDocument(readDoc); cmark_node *doc = Parser::parseContent(currentContent);
currentSourceCode = m_file.getSource(readDoc); m_renderArea.processDocument(doc);
m_file.free(readDoc); cmark_node_free(doc);
} catch (const std::runtime_error &error) { } catch (const std::runtime_error &error) {
m_renderArea.showMessage("Page not found!", "Detailed error message: " + std::string(error.what())); m_renderArea.showMessage("Page not found!", "Detailed error message: " + std::string(error.what()));
} }
@ -173,6 +171,6 @@ void MainWindow::openFromDisk()
void MainWindow::show_source_code_dialog() void MainWindow::show_source_code_dialog()
{ {
m_sourceCodeDialog.setText(currentSourceCode); m_sourceCodeDialog.setText(currentContent);
m_sourceCodeDialog.run(); m_sourceCodeDialog.run();
} }

View File

@ -16,45 +16,45 @@
class MainWindow : public Gtk::Window class MainWindow : public Gtk::Window
{ {
public: public:
MainWindow(); MainWindow();
protected: protected:
// Signal handlers: // Signal handlers:
// Our new improved on_button_clicked(). (see below) // Our new improved on_button_clicked(). (see below)
void go_home(); void go_home();
void input_activate(); void input_activate();
void on_button_clicked(Glib::ustring data); void on_button_clicked(Glib::ustring data);
void show_about(); void show_about();
void hide_about(int response); void hide_about(int response);
void show_source_code_dialog(); void show_source_code_dialog();
// Child widgets // Child widgets
Menu m_menu; Menu m_menu;
Gtk::Box m_vbox; Gtk::Box m_vbox;
Gtk::Box m_hbox_bar; Gtk::Box m_hbox_bar;
Gtk::Button m_backButton; Gtk::Button m_backButton;
Gtk::Button m_forwardButton; Gtk::Button m_forwardButton;
Gtk::Button m_refreshButton; Gtk::Button m_refreshButton;
Gtk::Button m_homeButton; Gtk::Button m_homeButton;
Gtk::Entry m_inputField; Gtk::Entry m_inputField;
Gtk::Image backIcon; Gtk::Image backIcon;
Gtk::Image forwardIcon; Gtk::Image forwardIcon;
Gtk::Image refreshIcon; Gtk::Image refreshIcon;
Gtk::Image homeIcon; Gtk::Image homeIcon;
Gtk::ScrolledWindow m_scrolledWindow; Gtk::ScrolledWindow m_scrolledWindow;
RenderArea m_renderArea; RenderArea m_renderArea;
SourceCodeDialog m_sourceCodeDialog; SourceCodeDialog m_sourceCodeDialog;
About m_about; About m_about;
private: private:
File m_file; File m_file;
std::string requestPath; std::string requestPath;
std::string finalRequestPath; std::string finalRequestPath;
std::string currentSourceCode; std::string currentContent;
void doRequest(const std::string &path = ""); void doRequest(const std::string &path = "");
void refresh(); void refresh();
void fetchFromIPFS(); void fetchFromIPFS();
void openFromDisk(); void openFromDisk();
}; };
#endif #endif

View File

@ -7,50 +7,39 @@
#include <syntax_extension.h> #include <syntax_extension.h>
#include <filesystem> #include <filesystem>
Parser::Parser(): options(CMARK_OPT_DEFAULT) {} static const int OPTIONS = CMARK_OPT_DEFAULT;
/// Meyers Singleton
Parser::Parser()= default;
/// Destructor
Parser::~Parser()= default;
/** /**
* Parse markdown by file path * \brief Get singleton instance
* @return AST structure (of type cmark_node) * \return Helper reference (singleton)
*/ */
cmark_node * Parser::parseFile(const std::string &filePath) Parser& Parser::getInstance() {
{ static Parser instance;
// Parse to AST with cmark return instance;
FILE *file;
if (!std::filesystem::exists(filePath.c_str())) {
throw std::runtime_error("File not found.");
}
if( ( file = fopen(filePath.c_str(), "r" ) ) != NULL )
{
cmark_node *doc;
// TODO: Copy/paste cmark_parse_file() content to here, allowing me to add extensions to the parser.
doc = cmark_parse_file(file, options);
fclose(file);
return doc;
} else {
throw std::runtime_error("File open failed.");
}
} }
/** /**
* Parse markdown file by stringstream * Parse markdown file from string content
* @return AST structure (of type cmark_node) * @return AST structure (of type cmark_node)
*/ */
cmark_node * Parser::parseStream(const std::stringstream &stream) cmark_node * Parser::parseContent(const std::string &content)
{ {
//cmark_node *doc; //cmark_node *doc;
// Parse to AST with cmark // Parse to AST with cmark
// mark_parser *parser = cmark_parser_new(options); // mark_parser *parser = cmark_parser_new(OPTIONS);
// Add extensions // Add extensions
//addMarkdownExtension(parser, "strikethrough"); //addMarkdownExtension(parser, "strikethrough");
//addMarkdownExtension(parser, "table"); //addMarkdownExtension(parser, "table");
const std::string tmp = stream.str(); const char *data = content.c_str();
const char *data = tmp.c_str();
// TODO: Copy cmark_parse_document() to be able to add extensions to the parser // TODO: Copy cmark_parse_document() to be able to add extensions to the parser
return cmark_parse_document(data, strlen(data), options); return cmark_parse_document(data, strlen(data), OPTIONS);
} }
/** /**
@ -58,18 +47,7 @@ cmark_node * Parser::parseStream(const std::stringstream &stream)
*/ */
std::string const Parser::renderHTML(cmark_node *node) std::string const Parser::renderHTML(cmark_node *node)
{ {
char *tmp = cmark_render_html(node, options, NULL); char *tmp = cmark_render_html(node, OPTIONS, NULL);
std::string output = std::string(tmp);
free(tmp);
return output;
}
/**
* Get just the plain text
*/
std::string const Parser::getSource(cmark_node *node)
{
char *tmp = cmark_render_commonmark(node, options, 0);
std::string output = std::string(tmp); std::string output = std::string(tmp);
free(tmp); free(tmp);
return output; return output;

View File

@ -11,14 +11,18 @@
class Parser class Parser
{ {
public: public:
Parser(); // Singleton
cmark_node * parseFile(const std::string &filePath); static Parser& getInstance();
cmark_node * parseStream(const std::stringstream &stream);
std::string const renderHTML(cmark_node *node); static cmark_node * parseContent(const std::string &content);
std::string const getSource(cmark_node *node); static std::string const renderHTML(cmark_node *node);
private: private:
int options; Parser();
void addMarkdownExtension(cmark_parser *parser, const char *extName); ~Parser();
Parser(const Parser&)= delete;
Parser& operator=(const Parser&)= delete;
static void addMarkdownExtension(cmark_parser *parser, const char *extName);
}; };
#endif #endif

View File

@ -16,6 +16,6 @@ public:
void fetchFile(const std::string& path, std::iostream* response); void fetchFile(const std::string& path, std::iostream* response);
private: private:
ipfs::Client m_client; ipfs::Client m_client;
}; };
#endif #endif

View File

@ -6,81 +6,81 @@
#include <cmark-gfm.h> #include <cmark-gfm.h>
struct text_struct { struct text_struct {
int x; int x;
int y; int y;
Glib::RefPtr<Pango::Layout> layout; Glib::RefPtr<Pango::Layout> layout;
}; };
struct line_struct { struct line_struct {
int start_x; int start_x;
int start_y; int start_y;
int end_x; // -1 means auto-size int end_x; // -1 means auto-size
int end_y; int end_y;
int margin_end_x; int margin_end_x;
double height; double height;
std::string hex_color; std::string hex_color;
Cairo::LineCap cap; Cairo::LineCap cap;
}; };
class RenderArea : public Gtk::DrawingArea class RenderArea : public Gtk::DrawingArea
{ {
public: public:
RenderArea(); RenderArea();
virtual ~RenderArea(); virtual ~RenderArea();
void processDocument(cmark_node *root_node); void processDocument(cmark_node *root_node);
void showMessage(const std::string &message, const std::string &detailed_info = ""); void showMessage(const std::string &message, const std::string &detailed_info = "");
void showStartPage(); void showStartPage();
protected: protected:
std::list<text_struct> m_textList; std::list<text_struct> m_textList;
std::list<line_struct> m_lines; std::list<line_struct> m_lines;
// Override default signal handler: // Override default signal handler:
bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr) override; bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr) override;
private: private:
int currentX; int currentX;
int currentY; int currentY;
int sceneMarginX; int sceneMarginX;
int sceneMarginY; int sceneMarginY;
int currentXList; int currentXList;
int headingLevel; int headingLevel;
int listLevel; int listLevel;
int wordSpacing; int wordSpacing;
int highestWidth; int highestWidth;
int highestHeight; int highestHeight;
int paragraphMargin; int paragraphMargin;
int headingMargin; int headingMargin;
int listMargin; int listMargin;
int horizontalLineMargin; int horizontalLineMargin;
int listXOffset; int listXOffset;
bool isBold; bool isBold;
bool isItalic; bool isItalic;
int bulletListLevel; int bulletListLevel;
int orderedListLevel; int orderedListLevel;
bool isOrderedList; bool isOrderedList;
std::map<int,int> orderedListCounters; std::map<int,int> orderedListCounters;
int fontSize; int fontSize;
std::string fontFamily; std::string fontFamily;
int pageWidth; int pageWidth;
int pageHeight; int pageHeight;
Pango::FontDescription defaultFont; Pango::FontDescription defaultFont;
Pango::FontDescription boldFont; Pango::FontDescription boldFont;
Pango::FontDescription italicFont; Pango::FontDescription italicFont;
Pango::FontDescription boldItalicFont; Pango::FontDescription boldItalicFont;
Pango::FontDescription heading1Font; Pango::FontDescription heading1Font;
Pango::FontDescription heading2Font; Pango::FontDescription heading2Font;
Pango::FontDescription heading3Font; Pango::FontDescription heading3Font;
Pango::FontDescription heading4Font; Pango::FontDescription heading4Font;
void createPangoContexts(); void createPangoContexts();
void clear(); void clear();
void processNode(cmark_node *node, cmark_event_type ev_type); void processNode(cmark_node *node, cmark_event_type ev_type);
void redraw(); void redraw();
std::string const intToRoman(int num); std::string const intToRoman(int num);
void hexToRGB(const std::string& hex, double &r, double &g, double &b); void hexToRGB(const std::string& hex, double &r, double &g, double &b);
}; };
#endif #endif

View File

@ -1,4 +1,3 @@
missingIncludeSystem missingIncludeSystem
missingInclude:lib/* missingInclude:lib/*
unusedFunction unusedFunction
unusedPrivateFunction