diff options
Diffstat (limited to 'src/gmdocument.c')
-rw-r--r-- | src/gmdocument.c | 69 |
1 files changed, 60 insertions, 9 deletions
diff --git a/src/gmdocument.c b/src/gmdocument.c index b1c3f2ef..67adb9cc 100644 --- a/src/gmdocument.c +++ b/src/gmdocument.c | |||
@@ -47,7 +47,7 @@ iBool isDark_GmDocumentTheme(enum iGmDocumentTheme d) { | |||
47 | iDeclareType(GmLink) | 47 | iDeclareType(GmLink) |
48 | 48 | ||
49 | struct Impl_GmLink { | 49 | struct Impl_GmLink { |
50 | iString url; | 50 | iString url; /* resolved */ |
51 | iRangecc urlRange; /* URL in the source */ | 51 | iRangecc urlRange; /* URL in the source */ |
52 | iRangecc labelRange; /* label in the source */ | 52 | iRangecc labelRange; /* label in the source */ |
53 | iRangecc labelIcon; /* special icon defined in the label text */ | 53 | iRangecc labelIcon; /* special icon defined in the label text */ |
@@ -74,8 +74,9 @@ iDefineTypeConstruction(GmLink) | |||
74 | struct Impl_GmDocument { | 74 | struct Impl_GmDocument { |
75 | iObject object; | 75 | iObject object; |
76 | enum iGmDocumentFormat format; | 76 | enum iGmDocumentFormat format; |
77 | iString source; | 77 | iString unormSource; /* unnormalized source */ |
78 | iString url; /* for resolving relative links */ | 78 | iString source; /* normalized source */ |
79 | iString url; /* for resolving relative links */ | ||
79 | iString localHost; | 80 | iString localHost; |
80 | iInt2 size; | 81 | iInt2 size; |
81 | iArray layout; /* contents of source, laid out in document space */ | 82 | iArray layout; /* contents of source, laid out in document space */ |
@@ -437,7 +438,10 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
437 | isFirstText = iFalse; | 438 | isFirstText = iFalse; |
438 | } | 439 | } |
439 | while (nextSplit_Rangecc(content, "\n", &contentLine)) { | 440 | while (nextSplit_Rangecc(content, "\n", &contentLine)) { |
440 | iRangecc line = contentLine; /* `line` will be trimmed later; would confuse nextSplit */ | 441 | iRangecc line = contentLine; /* `line` will be trimmed; modifying would confuse `nextSplit_Rangecc` */ |
442 | if (*line.end == '\r') { | ||
443 | line.end--; /* trim CR always */ | ||
444 | } | ||
441 | iGmRun run = { .color = white_ColorId }; | 445 | iGmRun run = { .color = white_ColorId }; |
442 | enum iGmLineType type; | 446 | enum iGmLineType type; |
443 | float indent = 0.0f; | 447 | float indent = 0.0f; |
@@ -857,10 +861,13 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
857 | } | 861 | } |
858 | } | 862 | } |
859 | } | 863 | } |
864 | printf("[GmDocument] layout size: %zu runs (%zu bytes)\n", | ||
865 | size_Array(&d->layout), size_Array(&d->layout) * sizeof(iGmRun)); | ||
860 | } | 866 | } |
861 | 867 | ||
862 | void init_GmDocument(iGmDocument *d) { | 868 | void init_GmDocument(iGmDocument *d) { |
863 | d->format = gemini_GmDocumentFormat; | 869 | d->format = gemini_GmDocumentFormat; |
870 | init_String(&d->unormSource); | ||
864 | init_String(&d->source); | 871 | init_String(&d->source); |
865 | init_String(&d->url); | 872 | init_String(&d->url); |
866 | init_String(&d->localHost); | 873 | init_String(&d->localHost); |
@@ -891,6 +898,7 @@ void deinit_GmDocument(iGmDocument *d) { | |||
891 | deinit_String(&d->localHost); | 898 | deinit_String(&d->localHost); |
892 | deinit_String(&d->url); | 899 | deinit_String(&d->url); |
893 | deinit_String(&d->source); | 900 | deinit_String(&d->source); |
901 | deinit_String(&d->unormSource); | ||
894 | } | 902 | } |
895 | 903 | ||
896 | iMedia *media_GmDocument(iGmDocument *d) { | 904 | iMedia *media_GmDocument(iGmDocument *d) { |
@@ -901,6 +909,7 @@ const iMedia *constMedia_GmDocument(const iGmDocument *d) { | |||
901 | return d->media; | 909 | return d->media; |
902 | } | 910 | } |
903 | 911 | ||
912 | #if 0 | ||
904 | void reset_GmDocument(iGmDocument *d) { | 913 | void reset_GmDocument(iGmDocument *d) { |
905 | clear_Media(d->media); | 914 | clear_Media(d->media); |
906 | clearLinks_GmDocument_(d); | 915 | clearLinks_GmDocument_(d); |
@@ -909,8 +918,11 @@ void reset_GmDocument(iGmDocument *d) { | |||
909 | clear_Array(&d->preMeta); | 918 | clear_Array(&d->preMeta); |
910 | clear_String(&d->url); | 919 | clear_String(&d->url); |
911 | clear_String(&d->localHost); | 920 | clear_String(&d->localHost); |
921 | clear_String(&d->source); | ||
922 | clear_String(&d->unormSource); | ||
912 | d->themeSeed = 0; | 923 | d->themeSeed = 0; |
913 | } | 924 | } |
925 | #endif | ||
914 | 926 | ||
915 | static void setDerivedThemeColors_(enum iGmDocumentTheme theme) { | 927 | static void setDerivedThemeColors_(enum iGmDocumentTheme theme) { |
916 | set_Color(tmQuoteIcon_ColorId, | 928 | set_Color(tmQuoteIcon_ColorId, |
@@ -1431,6 +1443,8 @@ static void normalize_GmDocument(iGmDocument *d) { | |||
1431 | isPreformat = iTrue; /* Cannot be turned off. */ | 1443 | isPreformat = iTrue; /* Cannot be turned off. */ |
1432 | } | 1444 | } |
1433 | const int preTabWidth = 4; /* TODO: user-configurable parameter */ | 1445 | const int preTabWidth = 4; /* TODO: user-configurable parameter */ |
1446 | iBool wasNormalized = iFalse; | ||
1447 | iBool hasTabs = iFalse; | ||
1434 | while (nextSplit_Rangecc(src, "\n", &line)) { | 1448 | while (nextSplit_Rangecc(src, "\n", &line)) { |
1435 | if (isPreformat) { | 1449 | if (isPreformat) { |
1436 | /* Replace any tab characters with spaces for visualization. */ | 1450 | /* Replace any tab characters with spaces for visualization. */ |
@@ -1441,10 +1455,16 @@ static void normalize_GmDocument(iGmDocument *d) { | |||
1441 | while (numSpaces-- > 0) { | 1455 | while (numSpaces-- > 0) { |
1442 | appendCStrN_String(normalized, " ", 1); | 1456 | appendCStrN_String(normalized, " ", 1); |
1443 | } | 1457 | } |
1458 | hasTabs = iTrue; | ||
1459 | wasNormalized = iTrue; | ||
1444 | } | 1460 | } |
1445 | else if (*ch != '\r') { | 1461 | else if (*ch != '\v') { |
1446 | appendCStrN_String(normalized, ch, 1); | 1462 | appendCStrN_String(normalized, ch, 1); |
1447 | } | 1463 | } |
1464 | else { | ||
1465 | hasTabs = iTrue; | ||
1466 | wasNormalized = iTrue; | ||
1467 | } | ||
1448 | } | 1468 | } |
1449 | appendCStr_String(normalized, "\n"); | 1469 | appendCStr_String(normalized, "\n"); |
1450 | if (d->format == gemini_GmDocumentFormat && | 1470 | if (d->format == gemini_GmDocumentFormat && |
@@ -1463,7 +1483,10 @@ static void normalize_GmDocument(iGmDocument *d) { | |||
1463 | int spaceCount = 0; | 1483 | int spaceCount = 0; |
1464 | for (const char *ch = line.start; ch != line.end; ch++) { | 1484 | for (const char *ch = line.start; ch != line.end; ch++) { |
1465 | char c = *ch; | 1485 | char c = *ch; |
1466 | if (c == '\r') continue; | 1486 | if (c == '\v') { |
1487 | wasNormalized = iTrue; | ||
1488 | continue; | ||
1489 | } | ||
1467 | if (isNormalizableSpace_(c)) { | 1490 | if (isNormalizableSpace_(c)) { |
1468 | if (isPrevSpace) { | 1491 | if (isPrevSpace) { |
1469 | if (++spaceCount == 8) { | 1492 | if (++spaceCount == 8) { |
@@ -1472,9 +1495,13 @@ static void normalize_GmDocument(iGmDocument *d) { | |||
1472 | popBack_Block(&normalized->chars); | 1495 | popBack_Block(&normalized->chars); |
1473 | pushBack_Block(&normalized->chars, '\t'); | 1496 | pushBack_Block(&normalized->chars, '\t'); |
1474 | } | 1497 | } |
1498 | wasNormalized = iTrue; | ||
1475 | continue; /* skip repeated spaces */ | 1499 | continue; /* skip repeated spaces */ |
1476 | } | 1500 | } |
1477 | c = ' '; | 1501 | if (c != ' ') { |
1502 | c = ' '; | ||
1503 | wasNormalized = iTrue; | ||
1504 | } | ||
1478 | isPrevSpace = iTrue; | 1505 | isPrevSpace = iTrue; |
1479 | } | 1506 | } |
1480 | else { | 1507 | else { |
@@ -1485,7 +1512,13 @@ static void normalize_GmDocument(iGmDocument *d) { | |||
1485 | } | 1512 | } |
1486 | appendCStr_String(normalized, "\n"); | 1513 | appendCStr_String(normalized, "\n"); |
1487 | } | 1514 | } |
1515 | printf("hasTabs: %d\n", hasTabs); | ||
1516 | printf("wasNormalized: %d\n", wasNormalized); | ||
1517 | fflush(stdout); | ||
1488 | set_String(&d->source, collect_String(normalized)); | 1518 | set_String(&d->source, collect_String(normalized)); |
1519 | printf("orig:%zu norm:%zu\n", size_String(&d->unormSource), size_String(&d->source)); | ||
1520 | /* normalized source has an extra newline at the end */ | ||
1521 | // iAssert(wasNormalized || equal_String(&d->unormSource, &d->source)); | ||
1489 | } | 1522 | } |
1490 | 1523 | ||
1491 | void setUrl_GmDocument(iGmDocument *d, const iString *url) { | 1524 | void setUrl_GmDocument(iGmDocument *d, const iString *url) { |
@@ -1496,8 +1529,18 @@ void setUrl_GmDocument(iGmDocument *d, const iString *url) { | |||
1496 | updateIconBasedOnUrl_GmDocument_(d); | 1529 | updateIconBasedOnUrl_GmDocument_(d); |
1497 | } | 1530 | } |
1498 | 1531 | ||
1499 | void setSource_GmDocument(iGmDocument *d, const iString *source, int width) { | 1532 | void setSource_GmDocument(iGmDocument *d, const iString *source, int width, |
1500 | set_String(&d->source, source); | 1533 | enum iGmDocumentUpdate updateType) { |
1534 | printf("[GmDocument] source update (%zu bytes), width:%d, final:%d\n", | ||
1535 | size_String(source), width, updateType == final_GmDocumentUpdate); | ||
1536 | if (size_String(source) == size_String(&d->unormSource)) { | ||
1537 | iAssert(equal_String(source, &d->unormSource)); | ||
1538 | printf("[GmDocument] source is unchanged!\n"); | ||
1539 | return; /* Nothing to do. */ | ||
1540 | } | ||
1541 | set_String(&d->unormSource, source); | ||
1542 | /* Normalize. */ | ||
1543 | set_String(&d->source, &d->unormSource); | ||
1501 | if (isNormalized_GmDocument_(d)) { | 1544 | if (isNormalized_GmDocument_(d)) { |
1502 | normalize_GmDocument(d); | 1545 | normalize_GmDocument(d); |
1503 | } | 1546 | } |
@@ -1599,6 +1642,14 @@ const iString *source_GmDocument(const iGmDocument *d) { | |||
1599 | return &d->source; | 1642 | return &d->source; |
1600 | } | 1643 | } |
1601 | 1644 | ||
1645 | size_t memorySize_GmDocument(const iGmDocument *d) { | ||
1646 | return size_String(&d->unormSource) + | ||
1647 | size_String(&d->source) + | ||
1648 | size_Array(&d->layout) * sizeof(iGmRun) + | ||
1649 | size_Array(&d->links) * sizeof(iGmLink) + | ||
1650 | memorySize_Media(d->media); | ||
1651 | } | ||
1652 | |||
1602 | iRangecc findText_GmDocument(const iGmDocument *d, const iString *text, const char *start) { | 1653 | iRangecc findText_GmDocument(const iGmDocument *d, const iString *text, const char *start) { |
1603 | const char * src = constBegin_String(&d->source); | 1654 | const char * src = constBegin_String(&d->source); |
1604 | const size_t startPos = (start ? start - src : 0); | 1655 | const size_t startPos = (start ? start - src : 0); |