From 07804493ac17ff430302c7940f44b7525c0620e8 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Sat, 29 Jan 2022 18:00:01 +0200 Subject: Hierarchical navigation with Gopher and Titan With Gopher, ensure that the item type changes to 1, and with Titan, change to normal Gemini. --- res/about/version.gmi | 2 ++ src/gmutil.c | 21 +++++++++++++++++++++ src/gmutil.h | 2 ++ src/gopher.c | 10 ++++++++++ src/gopher.h | 2 ++ src/ui/documentwidget.c | 28 ++++++++++++++++++++-------- 6 files changed, 57 insertions(+), 8 deletions(-) diff --git a/res/about/version.gmi b/res/about/version.gmi index a0cbe637..df532ab3 100644 --- a/res/about/version.gmi +++ b/res/about/version.gmi @@ -9,6 +9,8 @@ ## 1.10.3 * Added a man page. * "/index.gmi" is considered equal to "/" when navigating to parent directory. +* Gopher: Fixed navigating to root, e.g., when clicking on the page top banner. Set item type to 1 to show a gophermap and not the plain source. +* Titan: When navigating to parent/root, switch URL scheme to "gemini". This action occurs on a Titan response page, so initiating a new upload with the parent/root URL is probably not appropriate. * Fixed crash when a media player is active and a new download is started. * Fixed crash when a line contains nothing but an ANSI escape sequence. * Fixed a possible crash when saving state of subscribed feeds. diff --git a/src/gmutil.c b/src/gmutil.c index 98e4d4d6..b984950e 100644 --- a/src/gmutil.c +++ b/src/gmutil.c @@ -131,6 +131,16 @@ static iRangecc prevPathSeg_(const char *end, const char *start) { return seg; } +void stripUrlPort_String(iString *d) { + iUrl parts; + init_Url(&parts, d); + if (!isEmpty_Range(&parts.port)) { + /* Always preceded by a colon. */ + remove_Block(&d->chars, parts.port.start - 1 - constBegin_String(d), + size_Range(&parts.port) + 1); + } +} + void stripDefaultUrlPort_String(iString *d) { iUrl parts; init_Url(&parts, d); @@ -681,6 +691,17 @@ const iString *withSpacesEncoded_String(const iString *d) { return d; } +const iString *withScheme_String(const iString *d, const char *scheme) { + iUrl parts; + init_Url(&parts, d); + if (!equalCase_Rangecc(parts.scheme, scheme)) { + iString *repl = collectNewCStr_String(scheme); + appendRange_String(repl, (iRangecc){ parts.scheme.end, constEnd_String(d) }); + return repl; + } + return d; +} + const iString *canonicalUrl_String(const iString *d) { /* The "canonical" form, used for internal storage and comparisons, is: - all non-reserved characters decoded (i.e., it's an IRI) diff --git a/src/gmutil.h b/src/gmutil.h index 15bb7b2e..1594afc4 100644 --- a/src/gmutil.h +++ b/src/gmutil.h @@ -127,6 +127,7 @@ iBool isKnownScheme_Rangecc (iRangecc scheme); /* any URI scheme */ iBool isKnownUrlScheme_Rangecc(iRangecc scheme); /* URL schemes only */ void punyEncodeDomain_Rangecc(iRangecc domain, iString *encoded_out); void punyEncodeUrlHost_String(iString *absoluteUrl); +void stripUrlPort_String (iString *); void stripDefaultUrlPort_String(iString *); const iString * urlFragmentStripped_String(const iString *); const iString * urlQueryStripped_String (const iString *); @@ -138,6 +139,7 @@ const char * makeFileUrl_CStr (const char *localFilePath); iString * localFilePathFromUrl_String(const iString *); void urlEncodeSpaces_String (iString *); const iString * withSpacesEncoded_String(const iString *); +const iString * withScheme_String (const iString *, const char *scheme); /* replace URI scheme */ const iString * canonicalUrl_String (const iString *); const char * mediaType_Path (const iString *path); diff --git a/src/gopher.c b/src/gopher.c index 008a7743..0e34fe6a 100644 --- a/src/gopher.c +++ b/src/gopher.c @@ -299,3 +299,13 @@ iBool processResponse_Gopher(iGopher *d, const iBlock *data) { } return changed; } + +void setUrlItemType_Gopher(iString *url, char itemType) { + iUrl parts; + init_Url(&parts, url); + if (equalCase_Rangecc(parts.scheme, "gopher")) { + if (parts.path.start && size_Range(&parts.path) >= 2) { + ((char *) parts.path.start)[1] = itemType; + } + } +} diff --git a/src/gopher.h b/src/gopher.h index 3ad7e374..3cad0c21 100644 --- a/src/gopher.h +++ b/src/gopher.h @@ -44,3 +44,5 @@ iDeclareTypeConstruction(Gopher) void open_Gopher (iGopher *, const iString *url); iBool processResponse_Gopher (iGopher *, const iBlock *data); void cancel_Gopher (iGopher *); + +void setUrlItemType_Gopher (iString *url, char itemType); diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 2e15cdce..86513368 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -36,6 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "gmdocument.h" #include "gmrequest.h" #include "gmutil.h" +#include "gopher.h" #include "history.h" #include "indicatorwidget.h" #include "inputwidget.h" @@ -4315,20 +4316,31 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) } iString *parentUrl = collectNewRange_String((iRangecc){ constBegin_String(d->mod.url), parts.path.end }); - if (equalCase_Rangecc(parts.scheme, "gopher")) { - /* Always go to a gophermap. */ - iZap(parts); - init_Url(&parts, parentUrl); - if (parts.path.start && size_Range(&parts.path) >= 2) { - ((char *) parts.path.start)[1] = '1'; - } + /* Always go to a gophermap. */ + setUrlItemType_Gopher(parentUrl, '1'); + /* Hierarchical navigation doesn't make sense with Titan. */ + if (startsWith_String(parentUrl, "titan://")) { + /* We have no way of knowing if the corresponding URL is valid for Gemini, + but let's try anyway. */ + set_String(parentUrl, withScheme_String(parentUrl, "gemini")); + stripUrlPort_String(parentUrl); } postCommandf_Root(w->root, "open url:%s", cstr_String(parentUrl)); } return iTrue; } else if (equal_Command(cmd, "navigate.root") && document_App() == d) { - postCommandf_Root(w->root, "open url:%s/", cstr_Rangecc(urlRoot_String(d->mod.url))); + iString *rootUrl = collectNewRange_String(urlRoot_String(d->mod.url)); + /* Always go to a gophermap. */ + setUrlItemType_Gopher(rootUrl, '1'); + /* Hierarchical navigation doesn't make sense with Titan. */ + if (startsWith_String(rootUrl, "titan://")) { + /* We have no way of knowing if the corresponding URL is valid for Gemini, + but let's try anyway. */ + set_String(rootUrl, withScheme_String(rootUrl, "gemini")); + stripUrlPort_String(rootUrl); + } + postCommandf_Root(w->root, "open url:%s/", cstr_String(rootUrl)); return iTrue; } else if (equalWidget_Command(cmd, w, "scroll.moved")) { -- cgit v1.2.3