aboutsummaryrefslogtreecommitdiff
path: root/src/render/renderer.cc
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-04-11 05:36:22 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-04-11 05:36:22 +0800
commit4ef9c771444943008bb990343127a7d659fd6df2 (patch)
tree560b1c93f1950ddc5540999eae9b8d446e384470 /src/render/renderer.cc
parent5efb7400b96fa112c38009b18e2a48620f328148 (diff)
downloadrwebbrowser-4ef9c771444943008bb990343127a7d659fd6df2.tar.gz
rwebbrowser-4ef9c771444943008bb990343127a7d659fd6df2.tar.xz
feat: implement SSLSocket for encrypted connections and add terminal size detection utility
Diffstat (limited to 'src/render/renderer.cc')
-rw-r--r--src/render/renderer.cc38
1 files changed, 32 insertions, 6 deletions
diff --git a/src/render/renderer.cc b/src/render/renderer.cc
index 0a91d49..2115ee1 100644
--- a/src/render/renderer.cc
+++ b/src/render/renderer.cc
@@ -23,6 +23,25 @@ namespace ricochet::render {
namespace {
+std::string decode_entities( std::string text ) // NOLINT(readability-convert-member-functions-to-static)
+{
+ constexpr std::array<std::pair<std::string_view, std::string_view>, 24> entities
+ = { { { "&nbsp;", " " }, { "&lt;", "<" }, { "&gt;", ">" }, { "&amp;", "&" }, { "&quot;", "\"" },
+ { "&copy;", "©" }, { "&reg;", "®" }, { "&trade;", "™" }, { "&euro;", "€" }, { "&pound;", "£" },
+ { "&yen;", "¥" }, { "&cent;", "¢" }, { "&sect;", "§" }, { "&para;", "¶" }, { "&hellip;", "…" },
+ { "&dagger;", "†" }, { "&Dagger;", "‡" }, { "&bull;", "•" }, { "&prime;", "′" }, { "&Prime;", "″" },
+ { "&lsaquo;", "‹" }, { "&rsaquo;", "›" }, { "&oline;", "‾" }, { "&frasl;", "⁄" } } };
+
+ for ( const auto& [entity, replacement] : entities ) {
+ std::size_t pos = 0;
+ while ( ( pos = text.find( entity, pos ) ) != std::string::npos ) {
+ text.replace( pos, entity.length(), replacement );
+ pos += replacement.length();
+ }
+ }
+ return text;
+}
+
void render_node( const parser::DomNode& node, std::string& output ) // NOLINT(misc-no-recursion)
{
if ( node.tag_name == "head" || node.tag_name == "style" || node.tag_name == "script" || node.tag_name == "meta"
@@ -31,21 +50,27 @@ void render_node( const parser::DomNode& node, std::string& output ) // NOLINT(m
}
if ( node.tag_name.empty() ) {
- output += node.text_content;
+ output += decode_entities( node.text_content );
return;
}
- if ( node.tag_name == "h1" ) {
+
+ const bool is_header
+ = ( node.tag_name == "h1" || node.tag_name == "h2" || node.tag_name == "h3" || node.tag_name == "h4" );
+
+ if ( is_header ) {
output += "\n\n\033[1;31m";
} else if ( node.tag_name == "a" ) {
std::cout << "\033[4;34m";
- } else if ( node.tag_name == "p" || node.tag_name == "div" ) {
- output += "\n";
+ } else if ( node.tag_name == "p" || node.tag_name == "div" || is_header ) {
+ if ( !output.empty() && output.back() != '\n' ) {
+ output += "\n";
+ }
}
for ( const auto& child : node.children ) {
render_node( child, output );
}
- if ( node.tag_name == "h1" || node.tag_name == "a" ) {
+ if ( is_header || node.tag_name == "a" ) {
output += "\033[0m";
}
@@ -56,7 +81,8 @@ void render_node( const parser::DomNode& node, std::string& output ) // NOLINT(m
} // namespace
-std::string Renderer::render( const parser::DomNode& node ) const // NOLINT(readability-convert-member-functions-to-static)
+std::string Renderer::render( // NOLINT(readability-convert-member-functions-to-static)
+ const parser::DomNode& node ) const
{
std::string output;
render_node( node, output );