diff options
-rw-r--r-- | src/gmdocument.c | 24 | ||||
-rw-r--r-- | src/gmdocument.h | 1 | ||||
-rw-r--r-- | src/ui/text.h | 7 |
3 files changed, 32 insertions, 0 deletions
diff --git a/src/gmdocument.c b/src/gmdocument.c index 0d008181..54b7ad56 100644 --- a/src/gmdocument.c +++ b/src/gmdocument.c | |||
@@ -40,6 +40,7 @@ iDeclareType(GmLink) | |||
40 | struct Impl_GmLink { | 40 | struct Impl_GmLink { |
41 | iString url; | 41 | iString url; |
42 | iRangecc urlRange; /* URL in the source */ | 42 | iRangecc urlRange; /* URL in the source */ |
43 | iRangecc labelIcon; /* special icon defined in the label text */ | ||
43 | iTime when; | 44 | iTime when; |
44 | int flags; | 45 | int flags; |
45 | }; | 46 | }; |
@@ -227,9 +228,24 @@ static iRangecc addLink_GmDocument_(iGmDocument *d, iRangecc line, iGmLinkId *li | |||
227 | *linkId = size_PtrArray(&d->links); /* index + 1 */ | 228 | *linkId = size_PtrArray(&d->links); /* index + 1 */ |
228 | iRangecc desc = capturedRange_RegExpMatch(&m, 2); | 229 | iRangecc desc = capturedRange_RegExpMatch(&m, 2); |
229 | trim_Rangecc(&desc); | 230 | trim_Rangecc(&desc); |
231 | link->labelIcon = iNullRange; | ||
230 | if (!isEmpty_Range(&desc)) { | 232 | if (!isEmpty_Range(&desc)) { |
231 | line = desc; /* Just show the description. */ | 233 | line = desc; /* Just show the description. */ |
232 | link->flags |= humanReadable_GmLinkFlag; | 234 | link->flags |= humanReadable_GmLinkFlag; |
235 | /* Check for a custom icon. */ | ||
236 | if (link->flags & gemini_GmLinkFlag && ~link->flags & remote_GmLinkFlag) { | ||
237 | iChar icon = 0; | ||
238 | int len = 0; | ||
239 | if ((len = decodeBytes_MultibyteChar(desc.start, size_Range(&desc), &icon)) > 0) { | ||
240 | if (desc.start + len < desc.end && (isSymbol_Char(icon) || isEmoji_Char(icon)) && | ||
241 | !isFitzpatrickType_Char(icon)) { | ||
242 | link->flags |= iconFromLabel_GmLinkFlag; | ||
243 | link->labelIcon = (iRangecc){ desc.start, desc.start + len }; | ||
244 | line.start += len; | ||
245 | line.start = skipSpace_CStr(line.start); | ||
246 | } | ||
247 | } | ||
248 | } | ||
233 | } | 249 | } |
234 | else { | 250 | else { |
235 | line = capturedRange_RegExpMatch(&m, 1); /* Show the URL. */ | 251 | line = capturedRange_RegExpMatch(&m, 1); /* Show the URL. */ |
@@ -520,6 +536,10 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
520 | : link->flags & mailto_GmLinkFlag ? envelope | 536 | : link->flags & mailto_GmLinkFlag ? envelope |
521 | : link->flags & remote_GmLinkFlag ? globe | 537 | : link->flags & remote_GmLinkFlag ? globe |
522 | : arrow); | 538 | : arrow); |
539 | /* Custom link icon is shown on local Gemini links only. */ | ||
540 | if (!isEmpty_Range(&link->labelIcon)) { | ||
541 | icon.text = link->labelIcon; | ||
542 | } | ||
523 | icon.font = regular_FontId; | 543 | icon.font = regular_FontId; |
524 | if (link->flags & remote_GmLinkFlag) { | 544 | if (link->flags & remote_GmLinkFlag) { |
525 | icon.visBounds.pos.x -= gap_Text / 2; | 545 | icon.visBounds.pos.x -= gap_Text / 2; |
@@ -1450,6 +1470,10 @@ enum iColorId linkColor_GmDocument(const iGmDocument *d, iGmLinkId linkId, enum | |||
1450 | if (isUnsupported) { | 1470 | if (isUnsupported) { |
1451 | return tmBadLink_ColorId; | 1471 | return tmBadLink_ColorId; |
1452 | } | 1472 | } |
1473 | if (link->flags & iconFromLabel_GmLinkFlag) { | ||
1474 | return link->flags & visited_GmLinkFlag ? tmLinkTextHover_ColorId | ||
1475 | : tmLinkText_ColorId; | ||
1476 | } | ||
1453 | if (link->flags & visited_GmLinkFlag) { | 1477 | if (link->flags & visited_GmLinkFlag) { |
1454 | return link->flags & www_GmLinkFlag ? tmHypertextLinkIconVisited_ColorId | 1478 | return link->flags & www_GmLinkFlag ? tmHypertextLinkIconVisited_ColorId |
1455 | : link->flags & gopherOrFinger_GmLinkFlag ? tmGopherLinkIconVisited_ColorId | 1479 | : link->flags & gopherOrFinger_GmLinkFlag ? tmGopherLinkIconVisited_ColorId |
diff --git a/src/gmdocument.h b/src/gmdocument.h index 16127ea3..92f62ba4 100644 --- a/src/gmdocument.h +++ b/src/gmdocument.h | |||
@@ -69,6 +69,7 @@ enum iGmLinkFlags { | |||
69 | visited_GmLinkFlag = iBit(14), /* in the history */ | 69 | visited_GmLinkFlag = iBit(14), /* in the history */ |
70 | permanent_GmLinkFlag = iBit(15), /* content cannot be dismissed; media link */ | 70 | permanent_GmLinkFlag = iBit(15), /* content cannot be dismissed; media link */ |
71 | query_GmLinkFlag = iBit(16), /* Gopher query link */ | 71 | query_GmLinkFlag = iBit(16), /* Gopher query link */ |
72 | iconFromLabel_GmLinkFlag = iBit(17), /* use an Emoji/special character from label */ | ||
72 | }; | 73 | }; |
73 | 74 | ||
74 | struct Impl_GmHeading { | 75 | struct Impl_GmHeading { |
diff --git a/src/ui/text.h b/src/ui/text.h index acce286b..d57c2c62 100644 --- a/src/ui/text.h +++ b/src/ui/text.h | |||
@@ -140,6 +140,13 @@ iLocalDef iBool isEmoji_Char(iChar c) { | |||
140 | return (c >= 0x1f300 && c < 0x1f700) || (c >= 0x1f7e0 && c <= 0x1f7eb) || | 140 | return (c >= 0x1f300 && c < 0x1f700) || (c >= 0x1f7e0 && c <= 0x1f7eb) || |
141 | (c >= 0x1f900 && c <= 0x1f9ff); | 141 | (c >= 0x1f900 && c <= 0x1f9ff); |
142 | } | 142 | } |
143 | iLocalDef iBool isDingbats_Char(iChar c) { | ||
144 | return c >= 0x2702 && c <= 0x27b0; | ||
145 | } | ||
146 | iLocalDef iBool isSymbol_Char(iChar c) { | ||
147 | return (c == 0x2218 || c == 0x2219) || (c >= 0x1f680 && c <= 0x1f6c0) || | ||
148 | (c >= 0x2300 && c <= 0x26ff); | ||
149 | } | ||
143 | 150 | ||
144 | #define emojiVariationSelector_Char ((iChar) 0xfe0f) | 151 | #define emojiVariationSelector_Char ((iChar) 0xfe0f) |
145 | 152 | ||