mirror of
https://github.com/m1ngsama/TUT.git
synced 2026-02-08 00:54:05 +00:00
feat: Implement functional web browsing with HTTP + HTML rendering
Implemented the missing browser engine functionality to make TUT actually browse the web. Browser Engine Changes: - Integrate HttpClient to fetch URLs via GET requests - Integrate HtmlRenderer to parse and render HTML content - Implement proper error handling for failed HTTP requests - Add relative URL resolution for links (absolute and relative paths) - Store title, content, and links from rendered pages Tested with https://tldp.org/HOWTO/HOWTO-INDEX/howtos.html: ✅ Successfully fetches and displays web pages ✅ Renders HTML with proper formatting (headings, lists, links) ✅ Extracts and numbers clickable links ✅ Displays page titles The browser is now fully functional for basic text-based web browsing!
This commit is contained in:
parent
eea499e56e
commit
6baa6517ca
4 changed files with 64 additions and 17 deletions
|
|
@ -4,6 +4,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "core/browser_engine.hpp"
|
#include "core/browser_engine.hpp"
|
||||||
|
#include "core/http_client.hpp"
|
||||||
|
#include "renderer/html_renderer.hpp"
|
||||||
|
|
||||||
namespace tut {
|
namespace tut {
|
||||||
|
|
||||||
|
|
@ -15,6 +17,9 @@ public:
|
||||||
std::vector<LinkInfo> links_;
|
std::vector<LinkInfo> links_;
|
||||||
std::vector<std::string> history_;
|
std::vector<std::string> history_;
|
||||||
size_t history_index_{0};
|
size_t history_index_{0};
|
||||||
|
|
||||||
|
HttpClient http_client_;
|
||||||
|
HtmlRenderer renderer_;
|
||||||
};
|
};
|
||||||
|
|
||||||
BrowserEngine::BrowserEngine() : impl_(std::make_unique<Impl>()) {}
|
BrowserEngine::BrowserEngine() : impl_(std::make_unique<Impl>()) {}
|
||||||
|
|
@ -22,14 +27,66 @@ BrowserEngine::BrowserEngine() : impl_(std::make_unique<Impl>()) {}
|
||||||
BrowserEngine::~BrowserEngine() = default;
|
BrowserEngine::~BrowserEngine() = default;
|
||||||
|
|
||||||
bool BrowserEngine::loadUrl(const std::string& url) {
|
bool BrowserEngine::loadUrl(const std::string& url) {
|
||||||
// TODO: 实现 HTTP 请求和 HTML 解析
|
|
||||||
impl_->current_url_ = url;
|
impl_->current_url_ = url;
|
||||||
return true;
|
|
||||||
|
// 发送 HTTP 请求
|
||||||
|
auto response = impl_->http_client_.get(url);
|
||||||
|
|
||||||
|
if (!response.isSuccess()) {
|
||||||
|
// 加载失败,设置错误内容
|
||||||
|
impl_->title_ = "Error";
|
||||||
|
impl_->content_ = "Failed to load page: " +
|
||||||
|
(response.error.empty()
|
||||||
|
? "HTTP " + std::to_string(response.status_code)
|
||||||
|
: response.error);
|
||||||
|
impl_->links_.clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 渲染 HTML
|
||||||
|
return loadHtml(response.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BrowserEngine::loadHtml(const std::string& html) {
|
bool BrowserEngine::loadHtml(const std::string& html) {
|
||||||
// TODO: 实现 HTML 解析
|
// 渲染 HTML
|
||||||
impl_->content_ = html;
|
RenderOptions options;
|
||||||
|
options.show_links = true;
|
||||||
|
options.use_colors = true;
|
||||||
|
|
||||||
|
auto result = impl_->renderer_.render(html, options);
|
||||||
|
|
||||||
|
impl_->title_ = result.title;
|
||||||
|
impl_->content_ = result.text;
|
||||||
|
impl_->links_ = result.links;
|
||||||
|
|
||||||
|
// 解析相对 URL
|
||||||
|
if (!impl_->current_url_.empty()) {
|
||||||
|
for (auto& link : impl_->links_) {
|
||||||
|
if (link.url.find("://") == std::string::npos) {
|
||||||
|
// 简单的相对 URL 解析
|
||||||
|
if (!link.url.empty() && link.url[0] == '/') {
|
||||||
|
// 绝对路径
|
||||||
|
size_t scheme_end = impl_->current_url_.find("://");
|
||||||
|
if (scheme_end != std::string::npos) {
|
||||||
|
size_t host_end = impl_->current_url_.find('/', scheme_end + 3);
|
||||||
|
std::string base = (host_end != std::string::npos)
|
||||||
|
? impl_->current_url_.substr(0, host_end)
|
||||||
|
: impl_->current_url_;
|
||||||
|
link.url = base + link.url;
|
||||||
|
}
|
||||||
|
} else if (link.url.find("://") == std::string::npos &&
|
||||||
|
!link.url.empty() && link.url[0] != '#') {
|
||||||
|
// 相对路径
|
||||||
|
size_t last_slash = impl_->current_url_.rfind('/');
|
||||||
|
if (last_slash != std::string::npos) {
|
||||||
|
std::string base = impl_->current_url_.substr(0, last_slash + 1);
|
||||||
|
link.url = base + link.url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,18 +11,10 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include "types.hpp"
|
||||||
|
|
||||||
namespace tut {
|
namespace tut {
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 链接信息结构体
|
|
||||||
*/
|
|
||||||
struct LinkInfo {
|
|
||||||
std::string url; ///< 链接 URL
|
|
||||||
std::string text; ///< 链接文本
|
|
||||||
int line{0}; ///< 所在行号
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 浏览器引擎类
|
* @brief 浏览器引擎类
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,10 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include "../core/types.hpp"
|
||||||
|
|
||||||
namespace tut {
|
namespace tut {
|
||||||
|
|
||||||
struct LinkInfo;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 渲染选项
|
* @brief 渲染选项
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,10 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include "../core/types.hpp"
|
||||||
|
|
||||||
namespace tut {
|
namespace tut {
|
||||||
|
|
||||||
struct LinkInfo;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 内容视图组件类
|
* @brief 内容视图组件类
|
||||||
*
|
*
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue