summaryrefslogtreecommitdiff
path: root/src/gmdocument.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gmdocument.c')
-rw-r--r--src/gmdocument.c69
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) {
47iDeclareType(GmLink) 47iDeclareType(GmLink)
48 48
49struct Impl_GmLink { 49struct 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)
74struct Impl_GmDocument { 74struct 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
862void init_GmDocument(iGmDocument *d) { 868void 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
896iMedia *media_GmDocument(iGmDocument *d) { 904iMedia *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
904void reset_GmDocument(iGmDocument *d) { 913void 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
915static void setDerivedThemeColors_(enum iGmDocumentTheme theme) { 927static 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
1491void setUrl_GmDocument(iGmDocument *d, const iString *url) { 1524void 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
1499void setSource_GmDocument(iGmDocument *d, const iString *source, int width) { 1532void 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
1645size_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
1602iRangecc findText_GmDocument(const iGmDocument *d, const iString *text, const char *start) { 1653iRangecc 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);