srctree

Robin Linden parent 31c68278 a2beb7cf
Move tui rendering code into a separate library

inlinesplit
browser/BUILD added: 105, removed: 55, total 50
@@ -9,7 +9,7 @@ cc_binary(
}),
deps = [
"//html",
"//tui",
"@asio",
"@ftxui",
],
)
 
browser/main.cpp added: 105, removed: 55, total 50
@@ -1,13 +1,10 @@
#include "html/parser.h"
#include "tui/tui.h"
 
#include <ftxui/dom/elements.hpp>
#include <ftxui/screen/screen.hpp>
#include <ftxui/screen/string.hpp>
#include <asio.hpp> // Needs to be after ftxui due to pulling in macros that break their headers.
#include <asio.hpp>
 
#include <cassert>
#include <iostream>
#include <optional>
#include <sstream>
#include <string>
 
@@ -41,45 +38,6 @@ std::string drop_http_headers(std::string html) {
return html;
}
 
std::optional<ftxui::Element> create_ftxui_ui(dom::Node const &node) {
ftxui::Elements children;
for (auto const &child : node.children) {
if (auto n = create_ftxui_ui(child); n) {
children.push_back(*n);
}
};
 
return std::visit(overloaded {
[](std::monostate) -> std::optional<ftxui::Element> { return std::nullopt; },
[&](dom::Doctype const &) -> std::optional<ftxui::Element> { return std::nullopt; },
[&](dom::Element const &node) -> std::optional<ftxui::Element> {
if (node.name == "html") { return border(children[0]); }
else if (node.name == "body") { return vbox(children); }
else if (node.name == "div") { return flex(vbox(children)); }
else if (node.name == "h1") { return underlined(vbox(children)); }
else if (node.name == "p") { return flex(vbox(children)); }
else if (node.name == "a") { return bold(vbox(children)); }
else {
std::cout << "Unhandled node: " << node.name << '\n';
return std::nullopt;
}
},
[&](dom::Text const &node) -> std::optional<ftxui::Element> {
return hflow(ftxui::paragraph(ftxui::to_wstring(node.text)));
},
}, node.data);
}
 
void ftxui_test(dom::Node root) {
auto document = create_ftxui_ui(root);
if (!document) { return; }
std::cout << "\nBuilding TUI\n";
document = *document | ftxui::size(ftxui::WIDTH, ftxui::LESS_THAN, 80);
auto screen = ftxui::Screen::Create(ftxui::Dimension{80, 10});
ftxui::Render(screen, *document);
std::cout << screen.ToString() << std::endl;
}
 
} // namespace
 
int main(int argc, char **argv) {
@@ -98,5 +56,7 @@ int main(int argc, char **argv) {
 
auto nodes = html::Parser{buffer}.parse_nodes();
for (auto const &node : nodes) { print_node(node); }
for (auto const &node : nodes) { ftxui_test(node); }
 
std::cout << "\nBuilding TUI\n";
for (auto const &node : nodes) { std::cout << tui::render(node) << '\n'; }
}
 
dom/dom.h added: 105, removed: 55, total 50
@@ -26,15 +26,15 @@ struct Node {
std::variant<std::monostate, Doctype, Text, Element> data;
};
 
Node create_doctype_node(std::string_view doctype) {
inline Node create_doctype_node(std::string_view doctype) {
return {{}, Doctype{std::string{doctype}}};
}
 
Node create_text_node(std::string_view data) {
inline Node create_text_node(std::string_view data) {
return {{}, Text{std::string(data)}};
}
 
Node create_element_node(std::string_view name, AttrMap attrs, std::vector<Node> children) {
inline Node create_element_node(std::string_view name, AttrMap attrs, std::vector<Node> children) {
return {std::move(children), Element{std::string{name}, std::move(attrs)}};
}
 
 
filename was Deleted added: 105, removed: 55, total 50
@@ -0,0 +1,12 @@
load("@rules_cc//cc:defs.bzl", "cc_library")
 
cc_library(
name = "tui",
srcs = ["tui.cpp"],
hdrs = ["tui.h"],
visibility = ["//visibility:public"],
deps = [
"//dom",
"@ftxui",
],
)
 
filename was Deleted added: 105, removed: 55, total 50
@@ -0,0 +1,64 @@
#include "tui/tui.h"
 
#include <ftxui/dom/elements.hpp>
#include <ftxui/screen/screen.hpp>
#include <ftxui/screen/string.hpp>
 
#include <iostream>
#include <optional>
#include <string>
#include <variant>
 
namespace tui {
namespace {
 
template<class... Ts>
struct overloaded : Ts... { using Ts::operator()...; };
 
// Not needed as of C++20, but gcc 10 won't work without it.
template<class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;
 
std::optional<ftxui::Element> element_from_node(dom::Node const &node) {
ftxui::Elements children;
for (auto const &child : node.children) {
if (auto n = element_from_node(child); n) {
children.push_back(*n);
}
};
 
return std::visit(overloaded {
[](std::monostate) -> std::optional<ftxui::Element> { return std::nullopt; },
[&](dom::Doctype const &) -> std::optional<ftxui::Element> { return std::nullopt; },
[&](dom::Element const &node) -> std::optional<ftxui::Element> {
if (node.name == "html") { return border(children[0]); }
else if (node.name == "body") { return vbox(children); }
else if (node.name == "div") { return flex(vbox(children)); }
else if (node.name == "h1") { return underlined(vbox(children)); }
else if (node.name == "p") { return flex(vbox(children)); }
else if (node.name == "a") { return bold(vbox(children)); }
else {
std::cout << "Unhandled node: " << node.name << '\n';
return std::nullopt;
}
},
[&](dom::Text const &node) -> std::optional<ftxui::Element> {
return hflow(ftxui::paragraph(ftxui::to_wstring(node.text)));
},
}, node.data);
}
 
} // namespace
 
using namespace std::string_literals;
 
std::string render(dom::Node const &root) {
auto document = element_from_node(root);
if (!document) { return ""s; }
document = *document | ftxui::size(ftxui::WIDTH, ftxui::LESS_THAN, 80);
auto screen = ftxui::Screen::Create(ftxui::Dimension{80, 10});
ftxui::Render(screen, *document);
return screen.ToString();
}
 
} // namespace tui
 
filename was Deleted added: 105, removed: 55, total 50
@@ -0,0 +1,14 @@
#ifndef TUI_TUI_H_
#define TUI_TUI_H_
 
#include "dom/dom.h"
 
#include <string>
 
namespace tui {
 
std::string render(dom::Node const &root);
 
} // namespace tui
 
#endif