diff options
Diffstat (limited to 'src/gmdocument.c')
-rw-r--r-- | src/gmdocument.c | 86 |
1 files changed, 18 insertions, 68 deletions
diff --git a/src/gmdocument.c b/src/gmdocument.c index 19230392..b5e71e21 100644 --- a/src/gmdocument.c +++ b/src/gmdocument.c | |||
@@ -547,9 +547,11 @@ static void clear_RunTypesetter_(iRunTypesetter *d) { | |||
547 | clear_Array(&d->layout); | 547 | clear_Array(&d->layout); |
548 | } | 548 | } |
549 | 549 | ||
550 | static void commit_RunTypesetter_(iRunTypesetter *d, iGmDocument *doc) { | 550 | static size_t commit_RunTypesetter_(iRunTypesetter *d, iGmDocument *doc) { |
551 | const size_t n = size_Array(&d->layout); | ||
551 | pushBackN_Array(&doc->layout, constData_Array(&d->layout), size_Array(&d->layout)); | 552 | pushBackN_Array(&doc->layout, constData_Array(&d->layout), size_Array(&d->layout)); |
552 | clear_RunTypesetter_(d); | 553 | clear_RunTypesetter_(d); |
554 | return n; | ||
553 | } | 555 | } |
554 | 556 | ||
555 | static const int maxLedeLines_ = 10; | 557 | static const int maxLedeLines_ = 10; |
@@ -611,6 +613,10 @@ static iBool typesetOneLine_RunTypesetter_(iWrapText *wrap, iRangecc wrapRange, | |||
611 | } | 613 | } |
612 | 614 | ||
613 | static void doLayout_GmDocument_(iGmDocument *d) { | 615 | static void doLayout_GmDocument_(iGmDocument *d) { |
616 | static iRegExp *ansiPattern_; | ||
617 | if (!ansiPattern_) { | ||
618 | ansiPattern_ = makeAnsiEscapePattern_Text(iTrue /* with ESC */); | ||
619 | } | ||
614 | const iPrefs *prefs = prefs_App(); | 620 | const iPrefs *prefs = prefs_App(); |
615 | const iBool isMono = isForcedMonospace_GmDocument_(d); | 621 | const iBool isMono = isForcedMonospace_GmDocument_(d); |
616 | const iBool isGopher = isGopher_GmDocument_(d); | 622 | const iBool isGopher = isGopher_GmDocument_(d); |
@@ -618,8 +624,7 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
618 | const iBool isVeryNarrow = d->size.x <= 70 * gap_Text; | 624 | const iBool isVeryNarrow = d->size.x <= 70 * gap_Text; |
619 | const iBool isExtremelyNarrow = d->size.x <= 60 * gap_Text; | 625 | const iBool isExtremelyNarrow = d->size.x <= 60 * gap_Text; |
620 | const iBool isFullWidthImages = (d->outsideMargin < 5 * gap_UI); | 626 | const iBool isFullWidthImages = (d->outsideMargin < 5 * gap_UI); |
621 | // const iBool isDarkBg = isDark_GmDocumentTheme( | 627 | |
622 | // isDark_ColorTheme(colorTheme_App()) ? prefs->docThemeDark : prefs->docThemeLight); | ||
623 | initTheme_GmDocument_(d); | 628 | initTheme_GmDocument_(d); |
624 | d->isLayoutInvalidated = iFalse; | 629 | d->isLayoutInvalidated = iFalse; |
625 | /* TODO: Collect these parameters into a GmTheme. */ | 630 | /* TODO: Collect these parameters into a GmTheme. */ |
@@ -657,7 +662,6 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
657 | const iArray *oldPreMeta = collect_Array(copy_Array(&d->preMeta)); /* remember fold states */ | 662 | const iArray *oldPreMeta = collect_Array(copy_Array(&d->preMeta)); /* remember fold states */ |
658 | clear_Array(&d->preMeta); | 663 | clear_Array(&d->preMeta); |
659 | clear_String(&d->title); | 664 | clear_String(&d->title); |
660 | // clear_String(&d->bannerText); | ||
661 | if (d->size.x <= 0 || isEmpty_String(&d->source)) { | 665 | if (d->size.x <= 0 || isEmpty_String(&d->source)) { |
662 | return; | 666 | return; |
663 | } | 667 | } |
@@ -671,7 +675,6 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
671 | int preFont = preformatted_FontId; | 675 | int preFont = preformatted_FontId; |
672 | uint16_t preId = 0; | 676 | uint16_t preId = 0; |
673 | iBool enableIndents = iFalse; | 677 | iBool enableIndents = iFalse; |
674 | // iBool addSiteBanner = d->bannerType != none_GmDocumentBanner; | ||
675 | const iBool isNormalized = isNormalized_GmDocument_(d); | 678 | const iBool isNormalized = isNormalized_GmDocument_(d); |
676 | enum iGmLineType prevType = text_GmLineType; | 679 | enum iGmLineType prevType = text_GmLineType; |
677 | enum iGmLineType prevNonBlankType = text_GmLineType; | 680 | enum iGmLineType prevNonBlankType = text_GmLineType; |
@@ -755,7 +758,6 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
755 | if (d->format == gemini_SourceFormat && | 758 | if (d->format == gemini_SourceFormat && |
756 | startsWithSc_Rangecc(line, "```", &iCaseSensitive)) { | 759 | startsWithSc_Rangecc(line, "```", &iCaseSensitive)) { |
757 | isPreformat = iFalse; | 760 | isPreformat = iFalse; |
758 | // addSiteBanner = iFalse; /* overrides the banner */ | ||
759 | continue; | 761 | continue; |
760 | } | 762 | } |
761 | run.mediaType = max_MediaType; /* preformatted block */ | 763 | run.mediaType = max_MediaType; /* preformatted block */ |
@@ -763,28 +765,6 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
763 | run.font = (d->format == plainText_SourceFormat ? plainText_FontId : preFont); | 765 | run.font = (d->format == plainText_SourceFormat ? plainText_FontId : preFont); |
764 | indent = indents[type]; | 766 | indent = indents[type]; |
765 | } | 767 | } |
766 | #if 0 | ||
767 | if (addSiteBanner) { | ||
768 | addSiteBanner = iFalse; | ||
769 | const iRangecc bannerText = urlHost_String(&d->url); | ||
770 | if (!isEmpty_Range(&bannerText)) { | ||
771 | setRange_String(&d->bannerText, bannerText); | ||
772 | iGmRun banner = { .flags = decoration_GmRunFlag | siteBanner_GmRunFlag }; | ||
773 | banner.bounds = zero_Rect(); | ||
774 | banner.visBounds = init_Rect(0, 0, d->size.x, lineHeight_Text(banner_FontId) * 2); | ||
775 | if (d->bannerType == certificateWarning_GmDocumentBanner) { | ||
776 | banner.visBounds.size.y += iMaxi(6000 * lineHeight_Text(uiLabel_FontId) / | ||
777 | d->size.x, lineHeight_Text(uiLabel_FontId) * 5); | ||
778 | } | ||
779 | banner.text = bannerText; | ||
780 | banner.font = banner_FontId; | ||
781 | banner.color = tmBannerTitle_ColorId; | ||
782 | pushBack_Array(&d->layout, &banner); | ||
783 | pos.y += height_Rect(banner.visBounds) + | ||
784 | 1.5f * lineHeight_Text(paragraph_FontId) * prefs->lineSpacing; | ||
785 | } | ||
786 | } | ||
787 | #endif | ||
788 | /* Empty lines don't produce text runs. */ | 768 | /* Empty lines don't produce text runs. */ |
789 | if (isEmpty_Range(&line)) { | 769 | if (isEmpty_Range(&line)) { |
790 | if (type == quote_GmLineType && !prefs->quoteIcon) { | 770 | if (type == quote_GmLineType && !prefs->quoteIcon) { |
@@ -865,6 +845,8 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
865 | if ((type == heading1_GmLineType || type == heading2_GmLineType) && | 845 | if ((type == heading1_GmLineType || type == heading2_GmLineType) && |
866 | isEmpty_String(&d->title)) { | 846 | isEmpty_String(&d->title)) { |
867 | setRange_String(&d->title, line); | 847 | setRange_String(&d->title, line); |
848 | /* Get rid of ANSI escapes. */ | ||
849 | replaceRegExp_String(&d->title, ansiPattern_, "", NULL, NULL); | ||
868 | } | 850 | } |
869 | /* List bullet. */ | 851 | /* List bullet. */ |
870 | if (type == bullet_GmLineType) { | 852 | if (type == bullet_GmLineType) { |
@@ -964,6 +946,7 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
964 | } | 946 | } |
965 | } | 947 | } |
966 | iAssert(!isEmpty_Range(&line)); /* must have something at this point */ | 948 | iAssert(!isEmpty_Range(&line)); /* must have something at this point */ |
949 | size_t numRunsAdded = 0; | ||
967 | /* Typeset the paragraph. */ { | 950 | /* Typeset the paragraph. */ { |
968 | iRunTypesetter rts; | 951 | iRunTypesetter rts; |
969 | init_RunTypesetter_(&rts); | 952 | init_RunTypesetter_(&rts); |
@@ -1036,7 +1019,7 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
1036 | : 1.0f); | 1019 | : 1.0f); |
1037 | } | 1020 | } |
1038 | } | 1021 | } |
1039 | commit_RunTypesetter_(&rts, d); | 1022 | numRunsAdded = commit_RunTypesetter_(&rts, d); |
1040 | break; | 1023 | break; |
1041 | } | 1024 | } |
1042 | /* Try again... */ | 1025 | /* Try again... */ |
@@ -1050,6 +1033,11 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
1050 | deinit_RunTypesetter_(&rts); | 1033 | deinit_RunTypesetter_(&rts); |
1051 | } | 1034 | } |
1052 | /* Flag the end of line, too. */ | 1035 | /* Flag the end of line, too. */ |
1036 | if (numRunsAdded == 0) { | ||
1037 | pos.y += lineHeight_Text(run.font) * prefs->lineSpacing; | ||
1038 | followsBlank = iTrue; | ||
1039 | continue; | ||
1040 | } | ||
1053 | iGmRun *lastRun = back_Array(&d->layout); | 1041 | iGmRun *lastRun = back_Array(&d->layout); |
1054 | lastRun->flags |= endOfLine_GmRunFlag; | 1042 | lastRun->flags |= endOfLine_GmRunFlag; |
1055 | if (lastRun->linkId && lastRun->flags & startOfLine_GmRunFlag) { | 1043 | if (lastRun->linkId && lastRun->flags & startOfLine_GmRunFlag) { |
@@ -1301,7 +1289,7 @@ void setThemeSeed_GmDocument(iGmDocument *d, const iBlock *seed) { | |||
1301 | 0x203b, 0x2042, 0x205c, 0x2182, 0x25ed, 0x2600, 0x2601, 0x2604, 0x2605, 0x2606, | 1289 | 0x203b, 0x2042, 0x205c, 0x2182, 0x25ed, 0x2600, 0x2601, 0x2604, 0x2605, 0x2606, |
1302 | 0x265c, 0x265e, 0x2690, 0x2691, 0x2693, 0x2698, 0x2699, 0x26f0, 0x270e, 0x2728, | 1290 | 0x265c, 0x265e, 0x2690, 0x2691, 0x2693, 0x2698, 0x2699, 0x26f0, 0x270e, 0x2728, |
1303 | 0x272a, 0x272f, 0x2731, 0x2738, 0x273a, 0x273e, 0x2740, 0x2742, 0x2744, 0x2748, | 1291 | 0x272a, 0x272f, 0x2731, 0x2738, 0x273a, 0x273e, 0x2740, 0x2742, 0x2744, 0x2748, |
1304 | 0x274a, 0x2751, 0x2756, 0x2766, 0x27bd, 0x27c1, 0x27d0, 0x2b19, 0x1f300, 0x1f303, | 1292 | 0x274a, 0x2318, 0x2756, 0x2766, 0x27bd, 0x27c1, 0x27d0, 0x2b19, 0x1f300, 0x1f303, |
1305 | 0x1f306, 0x1f308, 0x1f30a, 0x1f319, 0x1f31f, 0x1f320, 0x1f340, 0x1f4cd, 0x1f4e1, 0x1f531, | 1293 | 0x1f306, 0x1f308, 0x1f30a, 0x1f319, 0x1f31f, 0x1f320, 0x1f340, 0x1f4cd, 0x1f4e1, 0x1f531, |
1306 | 0x1f533, 0x1f657, 0x1f659, 0x1f665, 0x1f668, 0x1f66b, 0x1f78b, 0x1f796, 0x1f79c, | 1294 | 0x1f533, 0x1f657, 0x1f659, 0x1f665, 0x1f668, 0x1f66b, 0x1f78b, 0x1f796, 0x1f79c, |
1307 | }; | 1295 | }; |
@@ -1951,44 +1939,6 @@ void setUrl_GmDocument(iGmDocument *d, const iString *url) { | |||
1951 | } | 1939 | } |
1952 | } | 1940 | } |
1953 | 1941 | ||
1954 | int replaceRegExp_String(iString *d, const iRegExp *regexp, const char *replacement, | ||
1955 | void (*matchHandler)(void *, const iRegExpMatch *), | ||
1956 | void *context) { | ||
1957 | iRegExpMatch m; | ||
1958 | iString result; | ||
1959 | int numMatches = 0; | ||
1960 | const char *pos = constBegin_String(d); | ||
1961 | init_RegExpMatch(&m); | ||
1962 | init_String(&result); | ||
1963 | while (matchString_RegExp(regexp, d, &m)) { | ||
1964 | appendRange_String(&result, (iRangecc){ pos, begin_RegExpMatch(&m) }); | ||
1965 | /* Replace any capture group back-references. */ | ||
1966 | for (const char *ch = replacement; *ch; ch++) { | ||
1967 | if (*ch == '\\') { | ||
1968 | ch++; | ||
1969 | if (*ch == '\\') { | ||
1970 | appendCStr_String(&result, "\\"); | ||
1971 | } | ||
1972 | else if (*ch >= '0' && *ch <= '9') { | ||
1973 | appendRange_String(&result, capturedRange_RegExpMatch(&m, *ch - '0')); | ||
1974 | } | ||
1975 | } | ||
1976 | else { | ||
1977 | appendData_Block(&result.chars, ch, 1); | ||
1978 | } | ||
1979 | } | ||
1980 | if (matchHandler) { | ||
1981 | matchHandler(context, &m); | ||
1982 | } | ||
1983 | pos = end_RegExpMatch(&m); | ||
1984 | numMatches++; | ||
1985 | } | ||
1986 | appendRange_String(&result, (iRangecc){ pos, constEnd_String(d) }); | ||
1987 | set_String(d, &result); | ||
1988 | deinit_String(&result); | ||
1989 | return numMatches; | ||
1990 | } | ||
1991 | |||
1992 | iDeclareType(PendingLink) | 1942 | iDeclareType(PendingLink) |
1993 | struct Impl_PendingLink { | 1943 | struct Impl_PendingLink { |
1994 | iString *url; | 1944 | iString *url; |