From 9f903612655ad5b0599feba628701195f026059d Mon Sep 17 00:00:00 2001 From: subhobhai943 Date: Thu, 27 Aug 2026 12:17:59 +0530 Subject: [PATCH] feat(gui): make the Web app a real browser -- clickable links, history, relative URLs The Web app fetched and rendered pages but could not browse between them. Now it does. In Reader view, anchors are parsed as the markup is stripped and recorded as links spanning the text they enclose; those spans render in the accent colour with an underline, and a click on one follows it. - Link capture: html_to_text now tracks open/close, storing each link's [start,end) span in the processed text plus its href in a per-page string pool. Rendering overlays link spans in accent + underline; a body click maps pixel -> line -> text offset -> containing link. - Relative resolution: a link's href is resolved against the page's own address (captured from the fetch's final host/port/path). Root-relative (/path), document-relative (page.html) and absolute URLs all work; the default port is omitted from the rebuilt URL. mailto:/javascript:/#frag are treated as non-navigable. - History: a back stack (depth 16) records each address before navigating; a Back button, lit only when there is somewhere to return to, pops it. - https:// links resolve through and are refused by the fetch layer with the existing clear message rather than being silently dropped. Verified on x86_64 with real synthetic clicks against a small multi-page HTTP site: the home page rendered its two links highlighted; clicking "Go to Page Two" navigated (URL bar updated to the resolved http://host/page2.html, host logged GET /page2.html) and Page Two rendered with its own links; the Back button returned to the home page (host logged GET /). Builds clean on x86_64, aarch64 and armv8i. Known limit: no TLS, so https:// pages are reported not shown -- plain HTTP browsing only. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX --- gui/gui_app_web.c | 271 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 251 insertions(+), 20 deletions(-) diff --git a/gui/gui_app_web.c b/gui/gui_app_web.c index 36d9d68..2c6f645 100644 --- a/gui/gui_app_web.c +++ b/gui/gui_app_web.c @@ -28,21 +28,48 @@ #define WEB_FETCH_CAP 16384 // response bytes retained #define WEB_MAX_LINES 2048 // rendered display lines retained +#define WEB_MAX_LINKS 400 // hyperlinks tracked per page +#define WEB_HREF_POOL 6144 // bytes of href strings per page +#define WEB_HISTORY 16 // back-stack depth #define WEB_URL_FIELD 1 +// A hyperlink: the [start,end) span it occupies in the processed text, and the +// offset of its href string in the pool. +typedef struct { + int start; + int end; + int href; +} web_link_t; + typedef struct { char url[256]; http_fetch_t* job; bool reader; // strip markup and reflow int scroll; // first visible display line - // Rendered line index, cached against the inputs that determine it. + // Rendered text and its line index, cached against the inputs that + // determine them. char* text; // processed text being displayed int text_len; int offsets[WEB_MAX_LINES]; int lengths[WEB_MAX_LINES]; int nlines; + // Links found while stripping markup (reader view only). + web_link_t links[WEB_MAX_LINKS]; + int nlinks; + char hrefs[WEB_HREF_POOL]; + int href_used; + + // The page's own address, used to resolve relative links. + char base_host[128]; + uint16_t base_port; + char base_path[256]; + + // Back stack of previously-visited URLs. + char hist[WEB_HISTORY][256]; + int hist_len; + const char* cache_src; // job->buf the cache was built from int cache_len; bool cache_reader; @@ -91,14 +118,58 @@ static char decode_entity(const char* e, int len) { return 0; } -// Strip markup from `src` into `out` (bounded by cap), collapsing runs of -// whitespace and turning block tags into single newlines.