summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-07-17 08:59:20 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-07-17 08:59:20 +0300
commit7e536572b602cba180ad4e85bd9c071479f6fa22 (patch)
tree6684609ee55ace94b3a65a48667f6c13a5cb12db
parent49656e357eb9741e8d44ae01d96268312e6fdc83 (diff)
GmDocument: Link scheme flags
A better way to keep track of the scheme used in a link.
-rw-r--r--src/defs.h1
-rw-r--r--src/gmdocument.c93
-rw-r--r--src/gmdocument.h46
-rw-r--r--src/gmrequest.h10
-rw-r--r--src/ui/documentwidget.c16
5 files changed, 99 insertions, 67 deletions
diff --git a/src/defs.h b/src/defs.h
index 5067cce3..6f58e749 100644
--- a/src/defs.h
+++ b/src/defs.h
@@ -72,6 +72,7 @@ enum iScrollType {
72#define whiteStar_Icon "\u2606" 72#define whiteStar_Icon "\u2606"
73#define person_Icon "\U0001f464" 73#define person_Icon "\U0001f464"
74#define download_Icon "\u2ba7" 74#define download_Icon "\u2ba7"
75#define upload_Icon "\u2ba5"
75#define export_Icon "\U0001f4e4" 76#define export_Icon "\U0001f4e4"
76#define hourglass_Icon "\u231b" 77#define hourglass_Icon "\u231b"
77#define timer_Icon "\u23f2" 78#define timer_Icon "\u23f2"
diff --git a/src/gmdocument.c b/src/gmdocument.c
index b403773a..7079d6e7 100644
--- a/src/gmdocument.c
+++ b/src/gmdocument.c
@@ -170,6 +170,11 @@ static iInt2 measurePreformattedBlock_GmDocument_(const iGmDocument *d, const ch
170 return measureRange_Text(font, *contents).bounds.size; 170 return measureRange_Text(font, *contents).bounds.size;
171} 171}
172 172
173static void setScheme_GmLink_(iGmLink *d, enum iGmLinkScheme scheme) {
174 d->flags &= ~supportedScheme_GmLinkFlag;
175 d->flags |= scheme;
176}
177
173static iRangecc addLink_GmDocument_(iGmDocument *d, iRangecc line, iGmLinkId *linkId) { 178static iRangecc addLink_GmDocument_(iGmDocument *d, iRangecc line, iGmLinkId *linkId) {
174 /* Returns the human-readable label of the link. */ 179 /* Returns the human-readable label of the link. */
175 static iRegExp *pattern_; 180 static iRegExp *pattern_;
@@ -189,32 +194,35 @@ static iRangecc addLink_GmDocument_(iGmDocument *d, iRangecc line, iGmLinkId *li
189 if (!equalCase_Rangecc(parts.host, cstr_String(&d->localHost))) { 194 if (!equalCase_Rangecc(parts.host, cstr_String(&d->localHost))) {
190 link->flags |= remote_GmLinkFlag; 195 link->flags |= remote_GmLinkFlag;
191 } 196 }
192 if (startsWithCase_Rangecc(parts.scheme, "gemini")) { 197 if (equalCase_Rangecc(parts.scheme, "gemini")) {
193 link->flags |= gemini_GmLinkFlag; 198 setScheme_GmLink_(link, gemini_GmLinkScheme);
199 }
200 else if (equalCase_Rangecc(parts.scheme, "titan")) {
201 setScheme_GmLink_(link, titan_GmLinkScheme);
194 } 202 }
195 else if (startsWithCase_Rangecc(parts.scheme, "http")) { 203 else if (startsWithCase_Rangecc(parts.scheme, "http")) {
196 link->flags |= http_GmLinkFlag; 204 setScheme_GmLink_(link, http_GmLinkScheme);
197 } 205 }
198 else if (equalCase_Rangecc(parts.scheme, "gopher")) { 206 else if (equalCase_Rangecc(parts.scheme, "gopher")) {
199 link->flags |= gopher_GmLinkFlag; 207 setScheme_GmLink_(link, gopher_GmLinkScheme);
200 if (startsWith_Rangecc(parts.path, "/7")) { 208 if (startsWith_Rangecc(parts.path, "/7")) {
201 link->flags |= query_GmLinkFlag; 209 link->flags |= query_GmLinkFlag;
202 } 210 }
203 } 211 }
204 else if (equalCase_Rangecc(parts.scheme, "finger")) { 212 else if (equalCase_Rangecc(parts.scheme, "finger")) {
205 link->flags |= finger_GmLinkFlag; 213 setScheme_GmLink_(link, finger_GmLinkScheme);
206 } 214 }
207 else if (equalCase_Rangecc(parts.scheme, "file")) { 215 else if (equalCase_Rangecc(parts.scheme, "file")) {
208 link->flags |= file_GmLinkFlag; 216 setScheme_GmLink_(link, file_GmLinkScheme);
209 } 217 }
210 else if (equalCase_Rangecc(parts.scheme, "data")) { 218 else if (equalCase_Rangecc(parts.scheme, "data")) {
211 link->flags |= data_GmLinkFlag; 219 setScheme_GmLink_(link, data_GmLinkScheme);
212 } 220 }
213 else if (equalCase_Rangecc(parts.scheme, "about")) { 221 else if (equalCase_Rangecc(parts.scheme, "about")) {
214 link->flags |= about_GmLinkFlag; 222 setScheme_GmLink_(link, about_GmLinkScheme);
215 } 223 }
216 else if (equalCase_Rangecc(parts.scheme, "mailto")) { 224 else if (equalCase_Rangecc(parts.scheme, "mailto")) {
217 link->flags |= mailto_GmLinkFlag; 225 setScheme_GmLink_(link, mailto_GmLinkScheme);
218 } 226 }
219 /* Check the file name extension, if present. */ 227 /* Check the file name extension, if present. */
220 if (!isEmpty_Range(&parts.path)) { 228 if (!isEmpty_Range(&parts.path)) {
@@ -252,8 +260,9 @@ static iRangecc addLink_GmDocument_(iGmDocument *d, iRangecc line, iGmLinkId *li
252 line = desc; /* Just show the description. */ 260 line = desc; /* Just show the description. */
253 link->flags |= humanReadable_GmLinkFlag; 261 link->flags |= humanReadable_GmLinkFlag;
254 /* Check for a custom icon. */ 262 /* Check for a custom icon. */
255 if ((link->flags & gemini_GmLinkFlag && ~link->flags & remote_GmLinkFlag) || 263 enum iGmLinkScheme scheme = scheme_GmLinkFlag(link->flags);
256 link->flags & file_GmLinkFlag) { 264 if ((scheme == gemini_GmLinkScheme && ~link->flags & remote_GmLinkFlag) ||
265 scheme == file_GmLinkScheme) {
257 iChar icon = 0; 266 iChar icon = 0;
258 int len = 0; 267 int len = 0;
259 if ((len = decodeBytes_MultibyteChar(desc.start, desc.end, &icon)) > 0) { 268 if ((len = decodeBytes_MultibyteChar(desc.start, desc.end, &icon)) > 0) {
@@ -484,10 +493,11 @@ static void doLayout_GmDocument_(iGmDocument *d) {
484 static const char *envelope = "\U0001f4e7"; 493 static const char *envelope = "\U0001f4e7";
485 static const char *bullet = "\u2022"; 494 static const char *bullet = "\u2022";
486 static const char *folder = "\U0001f4c1"; 495 static const char *folder = "\U0001f4c1";
487 static const char *globe = "\U0001f310"; 496 static const char *globe = globe_Icon;
488 static const char *quote = "\u201c"; 497 static const char *quote = "\u201c";
489 static const char *magnifyingGlass = "\U0001f50d"; 498 static const char *magnifyingGlass = "\U0001f50d";
490 static const char *pointingFinger = "\U0001f449"; 499 static const char *pointingFinger = "\U0001f449";
500 static const char *uploadArrow = upload_Icon;
491 clear_Array(&d->layout); 501 clear_Array(&d->layout);
492 clearLinks_GmDocument_(d); 502 clearLinks_GmDocument_(d);
493 clear_Array(&d->headings); 503 clear_Array(&d->headings);
@@ -739,10 +749,12 @@ static void doLayout_GmDocument_(iGmDocument *d) {
739 icon.visBounds.size = init_I2(indent * gap_Text, lineHeight_Text(run.textParams.font)); 749 icon.visBounds.size = init_I2(indent * gap_Text, lineHeight_Text(run.textParams.font));
740 icon.bounds = zero_Rect(); /* just visual */ 750 icon.bounds = zero_Rect(); /* just visual */
741 const iGmLink *link = constAt_PtrArray(&d->links, run.linkId - 1); 751 const iGmLink *link = constAt_PtrArray(&d->links, run.linkId - 1);
752 const enum iGmLinkScheme scheme = scheme_GmLinkFlag(link->flags);
742 icon.text = range_CStr(link->flags & query_GmLinkFlag ? magnifyingGlass 753 icon.text = range_CStr(link->flags & query_GmLinkFlag ? magnifyingGlass
743 : link->flags & file_GmLinkFlag ? folder 754 : scheme == file_GmLinkScheme ? folder
744 : link->flags & finger_GmLinkFlag ? pointingFinger 755 : scheme == titan_GmLinkScheme ? uploadArrow
745 : link->flags & mailto_GmLinkFlag ? envelope 756 : scheme == finger_GmLinkScheme ? pointingFinger
757 : scheme == mailto_GmLinkScheme ? envelope
746 : link->flags & remote_GmLinkFlag ? globe 758 : link->flags & remote_GmLinkFlag ? globe
747 : arrow); 759 : arrow);
748 /* Custom link icon is shown on local Gemini links only. */ 760 /* Custom link icon is shown on local Gemini links only. */
@@ -1951,12 +1963,21 @@ iMediaId linkAudio_GmDocument(const iGmDocument *d, iGmLinkId linkId) {
1951 return findLinkAudio_Media(d->media, linkId); 1963 return findLinkAudio_Media(d->media, linkId);
1952} 1964}
1953 1965
1966iLocalDef iBool isWWW_GmLinkScheme(enum iGmLinkScheme d) {
1967 return d == http_GmLinkScheme || d == mailto_GmLinkScheme;
1968}
1969
1970iLocalDef iBool isOldSchool_GmLinkScheme(enum iGmLinkScheme d) {
1971 return d == gopher_GmLinkScheme || d == finger_GmLinkScheme;
1972}
1973
1954enum iColorId linkColor_GmDocument(const iGmDocument *d, iGmLinkId linkId, enum iGmLinkPart part) { 1974enum iColorId linkColor_GmDocument(const iGmDocument *d, iGmLinkId linkId, enum iGmLinkPart part) {
1955 const iGmLink *link = link_GmDocument_(d, linkId); 1975 const iGmLink *link = link_GmDocument_(d, linkId);
1956 const int www_GmLinkFlag = http_GmLinkFlag | mailto_GmLinkFlag; 1976// const int www_GmLinkFlag = http_GmLinkFlag | mailto_GmLinkFlag;
1957 const int gopherOrFinger_GmLinkFlag = gopher_GmLinkFlag | finger_GmLinkFlag; 1977// const int gopherOrFinger_GmLinkFlag = gopher_GmLinkFlag | finger_GmLinkFlag;
1978 const enum iGmLinkScheme scheme = scheme_GmLinkFlag(link->flags);
1958 if (link) { 1979 if (link) {
1959 const iBool isUnsupported = (link->flags & supportedProtocol_GmLinkFlag) == 0; 1980 const iBool isUnsupported = (link->flags & supportedScheme_GmLinkFlag) == 0;
1960 if (part == icon_GmLinkPart) { 1981 if (part == icon_GmLinkPart) {
1961 if (isUnsupported) { 1982 if (isUnsupported) {
1962 return tmBadLink_ColorId; 1983 return tmBadLink_ColorId;
@@ -1966,36 +1987,36 @@ enum iColorId linkColor_GmDocument(const iGmDocument *d, iGmLinkId linkId, enum
1966 : tmLinkIcon_ColorId; 1987 : tmLinkIcon_ColorId;
1967 } 1988 }
1968 if (link->flags & visited_GmLinkFlag) { 1989 if (link->flags & visited_GmLinkFlag) {
1969 return link->flags & www_GmLinkFlag ? tmHypertextLinkIconVisited_ColorId 1990 return isWWW_GmLinkScheme(scheme) ? tmHypertextLinkIconVisited_ColorId
1970 : link->flags & gopherOrFinger_GmLinkFlag ? tmGopherLinkIconVisited_ColorId 1991 : isOldSchool_GmLinkScheme(scheme) ? tmGopherLinkIconVisited_ColorId
1971 : tmLinkIconVisited_ColorId; 1992 : tmLinkIconVisited_ColorId;
1972 } 1993 }
1973 return link->flags & www_GmLinkFlag ? tmHypertextLinkIcon_ColorId 1994 return isWWW_GmLinkScheme(scheme) ? tmHypertextLinkIcon_ColorId
1974 : link->flags & gopherOrFinger_GmLinkFlag ? tmGopherLinkIcon_ColorId 1995 : isOldSchool_GmLinkScheme(scheme) ? tmGopherLinkIcon_ColorId
1975 : tmLinkIcon_ColorId; 1996 : tmLinkIcon_ColorId;
1976 } 1997 }
1977 if (part == text_GmLinkPart) { 1998 if (part == text_GmLinkPart) {
1978 return link->flags & www_GmLinkFlag ? tmHypertextLinkText_ColorId 1999 return isWWW_GmLinkScheme(scheme) ? tmHypertextLinkText_ColorId
1979 : link->flags & gopherOrFinger_GmLinkFlag ? tmGopherLinkText_ColorId 2000 : isOldSchool_GmLinkScheme(scheme) ? tmGopherLinkText_ColorId
1980 : tmLinkText_ColorId; 2001 : tmLinkText_ColorId;
1981 } 2002 }
1982 if (part == textHover_GmLinkPart) { 2003 if (part == textHover_GmLinkPart) {
1983 return link->flags & www_GmLinkFlag ? tmHypertextLinkTextHover_ColorId 2004 return isWWW_GmLinkScheme(scheme) ? tmHypertextLinkTextHover_ColorId
1984 : link->flags & gopherOrFinger_GmLinkFlag ? tmGopherLinkTextHover_ColorId 2005 : isOldSchool_GmLinkScheme(scheme) ? tmGopherLinkTextHover_ColorId
1985 : tmLinkTextHover_ColorId; 2006 : tmLinkTextHover_ColorId;
1986 } 2007 }
1987 if (part == domain_GmLinkPart) { 2008 if (part == domain_GmLinkPart) {
1988 if (isUnsupported) { 2009 if (isUnsupported) {
1989 return tmBadLink_ColorId; 2010 return tmBadLink_ColorId;
1990 } 2011 }
1991 return link->flags & www_GmLinkFlag ? tmHypertextLinkDomain_ColorId 2012 return isWWW_GmLinkScheme(scheme) ? tmHypertextLinkDomain_ColorId
1992 : link->flags & gopherOrFinger_GmLinkFlag ? tmGopherLinkDomain_ColorId 2013 : isOldSchool_GmLinkScheme(scheme) ? tmGopherLinkDomain_ColorId
1993 : tmLinkDomain_ColorId; 2014 : tmLinkDomain_ColorId;
1994 } 2015 }
1995 if (part == visited_GmLinkPart) { 2016 if (part == visited_GmLinkPart) {
1996 return link->flags & www_GmLinkFlag ? tmHypertextLinkLastVisitDate_ColorId 2017 return isWWW_GmLinkScheme(scheme) ? tmHypertextLinkLastVisitDate_ColorId
1997 : link->flags & gopherOrFinger_GmLinkFlag ? tmGopherLinkLastVisitDate_ColorId 2018 : isOldSchool_GmLinkScheme(scheme) ? tmGopherLinkLastVisitDate_ColorId
1998 : tmLinkLastVisitDate_ColorId; 2019 : tmLinkLastVisitDate_ColorId;
1999 } 2020 }
2000 } 2021 }
2001 return tmLinkText_ColorId; 2022 return tmLinkText_ColorId;
diff --git a/src/gmdocument.h b/src/gmdocument.h
index 9d906006..9a7a70df 100644
--- a/src/gmdocument.h
+++ b/src/gmdocument.h
@@ -65,28 +65,36 @@ iBool isDark_GmDocumentTheme(enum iGmDocumentTheme);
65 65
66typedef uint16_t iGmLinkId; 66typedef uint16_t iGmLinkId;
67 67
68enum iGmLinkScheme {
69 gemini_GmLinkScheme = 1,
70 titan_GmLinkScheme,
71 gopher_GmLinkScheme,
72 finger_GmLinkScheme,
73 http_GmLinkScheme,
74 file_GmLinkScheme,
75 data_GmLinkScheme,
76 about_GmLinkScheme,
77 mailto_GmLinkScheme,
78};
79
68enum iGmLinkFlag { 80enum iGmLinkFlag {
69 gemini_GmLinkFlag = iBit(1), 81 supportedScheme_GmLinkFlag = 0x3f, /* mask of bits 1...6 */
70 gopher_GmLinkFlag = iBit(2), 82 remote_GmLinkFlag = iBit(7),
71 finger_GmLinkFlag = iBit(3), 83 humanReadable_GmLinkFlag = iBit(8), /* link has a human-readable description */
72 http_GmLinkFlag = iBit(4), 84 imageFileExtension_GmLinkFlag = iBit(9),
73 file_GmLinkFlag = iBit(5), 85 audioFileExtension_GmLinkFlag = iBit(10),
74 data_GmLinkFlag = iBit(6), 86 content_GmLinkFlag = iBit(11), /* content visible below */
75 about_GmLinkFlag = iBit(7), 87 visited_GmLinkFlag = iBit(12), /* in the history */
76 mailto_GmLinkFlag = iBit(8), 88 permanent_GmLinkFlag = iBit(13), /* content cannot be dismissed; media link */
77 supportedProtocol_GmLinkFlag = 0xff, 89 query_GmLinkFlag = iBit(14), /* Gopher query link */
78 remote_GmLinkFlag = iBit(9), 90 iconFromLabel_GmLinkFlag = iBit(15), /* use an Emoji/special character from label */
79 humanReadable_GmLinkFlag = iBit(10), /* link has a human-readable description */ 91 isOpen_GmLinkFlag = iBit(16), /* currently open in a tab */
80 imageFileExtension_GmLinkFlag = iBit(11),
81 audioFileExtension_GmLinkFlag = iBit(12),
82 content_GmLinkFlag = iBit(13), /* content visible below */
83 visited_GmLinkFlag = iBit(14), /* in the history */
84 permanent_GmLinkFlag = iBit(15), /* content cannot be dismissed; media link */
85 query_GmLinkFlag = iBit(16), /* Gopher query link */
86 iconFromLabel_GmLinkFlag = iBit(17), /* use an Emoji/special character from label */
87 isOpen_GmLinkFlag = iBit(18), /* currently open in a tab */
88}; 92};
89 93
94iLocalDef enum iGmLinkScheme scheme_GmLinkFlag(int flags) {
95 return flags & supportedScheme_GmLinkFlag;
96}
97
90struct Impl_GmHeading { 98struct Impl_GmHeading {
91 iRangecc text; 99 iRangecc text;
92 int level; /* 0, 1, 2 */ 100 int level; /* 0, 1, 2 */
diff --git a/src/gmrequest.h b/src/gmrequest.h
index 48b672ef..2b1f1bdd 100644
--- a/src/gmrequest.h
+++ b/src/gmrequest.h
@@ -31,11 +31,11 @@ iDeclareType(GmCerts)
31iDeclareType(GmResponse) 31iDeclareType(GmResponse)
32 32
33enum iGmCertFlag { 33enum iGmCertFlag {
34 available_GmCertFlag = iBit(1), /* certificate provided by server */ 34 available_GmCertFlag = iBit(1), /* certificate provided by server */
35 trusted_GmCertFlag = iBit(2), /* TOFU status */ 35 trusted_GmCertFlag = iBit(2), /* TOFU status */
36 timeVerified_GmCertFlag = iBit(3), /* has not expired */ 36 timeVerified_GmCertFlag = iBit(3), /* has not expired */
37 domainVerified_GmCertFlag = iBit(4), /* cert matches server domain */ 37 domainVerified_GmCertFlag = iBit(4), /* cert matches server domain */
38 haveFingerprint_GmCertFlag = iBit(5), 38 haveFingerprint_GmCertFlag = iBit(5),
39 authorityVerified_GmCertFlag = iBit(6), 39 authorityVerified_GmCertFlag = iBit(6),
40}; 40};
41 41
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 53f5d09b..8072a025 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -3857,7 +3857,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
3857 } 3857 }
3858 refresh_Widget(w); 3858 refresh_Widget(w);
3859 } 3859 }
3860 else if (linkFlags & supportedProtocol_GmLinkFlag) { 3860 else if (linkFlags & supportedScheme_GmLinkFlag) {
3861 int tabMode = openTabMode_Sym(modState_Keys()); 3861 int tabMode = openTabMode_Sym(modState_Keys());
3862 if (isPinned_DocumentWidget_(d)) { 3862 if (isPinned_DocumentWidget_(d)) {
3863 tabMode ^= otherRoot_OpenTabFlag; 3863 tabMode ^= otherRoot_OpenTabFlag;
@@ -4309,8 +4309,10 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
4309 iUrl parts; 4309 iUrl parts;
4310 init_Url(&parts, url); 4310 init_Url(&parts, url);
4311 fg = linkColor_GmDocument(doc, linkId, textHover_GmLinkPart); 4311 fg = linkColor_GmDocument(doc, linkId, textHover_GmLinkPart);
4312 const enum iGmLinkScheme scheme = scheme_GmLinkFlag(flags);
4312 const iBool showHost = (flags & humanReadable_GmLinkFlag && 4313 const iBool showHost = (flags & humanReadable_GmLinkFlag &&
4313 (!isEmpty_Range(&parts.host) || flags & mailto_GmLinkFlag)); 4314 (!isEmpty_Range(&parts.host) ||
4315 scheme == mailto_GmLinkScheme));
4314 const iBool showImage = (flags & imageFileExtension_GmLinkFlag) != 0; 4316 const iBool showImage = (flags & imageFileExtension_GmLinkFlag) != 0;
4315 const iBool showAudio = (flags & audioFileExtension_GmLinkFlag) != 0; 4317 const iBool showAudio = (flags & audioFileExtension_GmLinkFlag) != 0;
4316 iString str; 4318 iString str;
@@ -4324,11 +4326,11 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
4324 "%s%s%s%s%s", 4326 "%s%s%s%s%s",
4325 showHost ? "" : "", 4327 showHost ? "" : "",
4326 showHost 4328 showHost
4327 ? (flags & mailto_GmLinkFlag ? cstr_String(url) 4329 ? (scheme == mailto_GmLinkScheme ? cstr_String(url)
4328 : ~flags & gemini_GmLinkFlag ? format_CStr("%s://%s", 4330 : scheme != gemini_GmLinkScheme ? format_CStr("%s://%s",
4329 cstr_Rangecc(parts.scheme), 4331 cstr_Rangecc(parts.scheme),
4330 cstr_Rangecc(parts.host)) 4332 cstr_Rangecc(parts.host))
4331 : cstr_Rangecc(parts.host)) 4333 : cstr_Rangecc(parts.host))
4332 : "", 4334 : "",
4333 showHost && (showImage || showAudio) ? " \u2014" : "", 4335 showHost && (showImage || showAudio) ? " \u2014" : "",
4334 showImage || showAudio 4336 showImage || showAudio