Skip to content

Instantly share code, notes, and snippets.

@deton
Last active June 5, 2022 11:14
Show Gist options
  • Select an option

  • Save deton/2d11d1ff1cb5e2a8ded9fef6af6f6266 to your computer and use it in GitHub Desktop.

Select an option

Save deton/2d11d1ff1cb5e2a8ded9fef6af6f6266 to your computer and use it in GitHub Desktop.
Lynx patch to add H1-H6 headings link list to List Page
diff --git a/src/GridText.c b/src/GridText.c
index d9a1665..b3c41e0 100644
--- a/src/GridText.c
+++ b/src/GridText.c
@@ -6257,6 +6257,34 @@ HTChildAnchor *HText_childNextNumber(int number, void **prev)
return a->anchor;
}
+#ifdef EXP_HEADINGLIST
+/* returns not only HREF anchor which has number
+ * but also NAME or ID attribute anchor */
+HTChildAnchor *HText_childNext(void **prev)
+{
+ TextAnchor *a = (TextAnchor *) *prev;
+
+ if (!HTMainText)
+ return (HTChildAnchor *) 0; /* Fail */
+ if (!a)
+ a = HTMainText->first_anchor;
+ else
+ a = a->next;
+
+ for (; a != 0; a = a->next) {
+ if (a->number > 0) /* HREF anchor */
+ break;
+ if (a->anchor && a->anchor->tag) /* NAME or ID attribute anchor */
+ break;
+ }
+
+ if (!a)
+ return (HTChildAnchor *) 0; /* Fail */
+ *prev = (void *) a;
+ return a->anchor;
+}
+#endif /* EXP_HEADINGLIST */
+
/*
* For the -unique-urls option, find the anchor-number of the first occurrence
* of a given address.
@@ -9573,6 +9601,49 @@ const char *HText_HiddenLinkAt(HText *text, int number)
return (href);
}
+#ifdef EXP_HEADINGLIST
+int HText_PoundCount(BOOL onlyLynxHeading)
+{
+ int count = 0;
+ TextAnchor *a;
+
+ for (a = HTMainText->first_anchor; a != 0; a = a->next) {
+ if (a->anchor && non_empty(a->anchor->tag)) {
+ if (!onlyLynxHeading)
+ count++;
+ else if (isLYNXHEADING(a->anchor->tag))
+ count++;
+ }
+ }
+ return (count);
+}
+
+HTChildAnchor *HText_PoundNext(BOOL onlyLynxHeading, int *linenum, void **prev)
+{
+ TextAnchor *a = (TextAnchor *) *prev;
+ *linenum = 0;
+
+ if (!HTMainText)
+ return (HTChildAnchor *) 0; /* Fail */
+ if (!a)
+ a = HTMainText->first_anchor;
+
+ for (; a != 0; a = a->next)
+ if (a->anchor && non_empty(a->anchor->tag)) {
+ if (!onlyLynxHeading)
+ break;
+ else if (isLYNXHEADING(a->anchor->tag))
+ break;
+ }
+
+ if (!a)
+ return (HTChildAnchor *) 0; /* Fail */
+ *prev = (void *) a->next;
+ *linenum = a->line_num;
+ return a->anchor;
+}
+#endif /* EXP_HEADINGLIST */
+
/*
* Form methods
* These routines are used to build forms consisting
diff --git a/src/GridText.h b/src/GridText.h
index 40b17b1..c53925f 100644
--- a/src/GridText.h
+++ b/src/GridText.h
@@ -183,6 +183,11 @@ US-ASCII control characters <32 which are not defined in Unicode standard
extern void HText_setNodeAnchorBookmark(const char *bookmark);
extern void HText_setTabID(HText *text, const char *name);
extern void *HText_pool_calloc(HText *text, unsigned size);
+#ifdef EXP_HEADINGLIST
+ extern HTChildAnchor *HText_childNext(void **prev);
+ extern int HText_PoundCount(BOOL onlyLynxHeading);
+ extern HTChildAnchor *HText_PoundNext(BOOL onlyLynxHeading, int *linenum, void **prev);
+#endif
/* "simple table" stuff */
extern BOOLEAN HText_endStblTABLE(HText *);
diff --git a/src/HTML.c b/src/HTML.c
index 3ab8373..04c9b8a 100644
--- a/src/HTML.c
+++ b/src/HTML.c
@@ -1835,6 +1839,9 @@ static int HTML_start_element(HTStructured * me, int element_number,
me->inP = FALSE;
}
CHECK_ID(HTML_H_ID);
+#ifdef EXP_HEADINGLIST
+ LYAddHeadingID(me, ElementNumber);
+#endif
break;
}
@@ -1862,6 +1869,9 @@ static int HTML_start_element(HTStructured * me, int element_number,
}
UPDATE_STYLE;
CHECK_ID(HTML_H_ID);
+#ifdef EXP_HEADINGLIST
+ LYAddHeadingID(me, ElementNumber);
+#endif
if ((bold_headers == TRUE ||
(ElementNumber == HTML_H1 && bold_H1 == TRUE)) &&
@@ -7583,6 +7593,9 @@ HTStructured *HTML_new(HTParentAnchor *anchor,
me->CurrentANum = 0;
me->base_href = NULL;
me->map_address = NULL;
+#ifdef EXP_HEADINGLIST
+ me->nextHeadingSeqNum = 0;
+#endif
HTChunkInit(&me->title, 128);
diff --git a/src/HTML.h b/src/HTML.h
index 9f5d1d5..0fcd1c8 100644
--- a/src/HTML.h
+++ b/src/HTML.h
@@ -75,6 +75,9 @@ extern "C" {
int CurrentANum; /* current HTML_A number */
char *base_href; /* current HTML_BASE href */
char *map_address; /* current HTML_MAP address */
+#ifdef EXP_HEADINGLIST
+ int nextHeadingSeqNum; /* next HTML_H# sequence number */
+#endif
HTChunk title; /* Grow by 128 */
HTChunk object; /* Grow by 128 */
diff --git a/src/LYCharUtils.c b/src/LYCharUtils.c
index 03b2e81..8461ff7 100644
--- a/src/LYCharUtils.c
+++ b/src/LYCharUtils.c
@@ -3135,6 +3135,32 @@ void LYHandleID(HTStructured * me, const char *id)
}
}
+#ifdef EXP_HEADINGLIST
+void LYAddHeadingID(HTStructured * me, int element_number)
+{
+ HTChildAnchor *ID_A = NULL;
+ char *id = 0;
+
+ if (!(me && me->text))
+ return;
+
+ HTSprintf0(&id, "%s%d_H%d", STR_LYNXHEADING, me->nextHeadingSeqNum,
+ element_number - HTML_H1 + 1);
+ me->nextHeadingSeqNum++;
+
+ if ((ID_A = HTAnchor_findChildAndLink
+ (
+ me->node_anchor, /* Parent */
+ id, /* Tag */
+ NULL, /* Address */
+ (HTLinkType *) 0)) != NULL) { /* Type */
+ HText_beginAnchor(me->text, me->inUnderline, ID_A);
+ HText_endAnchor(me->text, 0);
+ }
+ FREE(id);
+}
+#endif /* EXP_HEADINGLIST */
+
/*
* This function checks whether we want to override
* the current default alignment for paragraphs and
diff --git a/src/LYCharUtils.h b/src/LYCharUtils.h
index 2b9ca88..8ffc4f8 100644
--- a/src/LYCharUtils.h
+++ b/src/LYCharUtils.h
@@ -92,6 +92,9 @@ extern "C" {
STRING2PTR value,
int attribute);
extern void LYHandleID(HTStructured * me, const char *id);
+#ifdef EXP_HEADINGLIST
+ extern void LYAddHeadingID(HTStructured * me, int element_number);
+#endif
extern BOOLEAN LYoverride_default_alignment(HTStructured * me);
extern void LYEnsureDoubleSpace(HTStructured * me);
extern void LYEnsureSingleSpace(HTStructured * me);
diff --git a/src/LYList.c b/src/LYList.c
index 989b6a3..dc0a1bf 100644
--- a/src/LYList.c
+++ b/src/LYList.c
@@ -44,6 +44,9 @@ int showlist(DocInfo *newdoc, int titles)
{
int cnt;
int refs, hidden_links;
+#ifdef EXP_HEADINGLIST
+ int pounds;
+#endif
int result;
static char tempfile[LY_MAXPATH];
static BOOLEAN last_titles = TRUE;
@@ -56,12 +59,23 @@ int showlist(DocInfo *newdoc, int titles)
refs = HText_sourceAnchors(HTMainText);
hidden_links = HText_HiddenLinkCount(HTMainText);
+#ifdef EXP_HEADINGLIST
+ pounds = HText_PoundCount(TRUE);
+#endif
if (refs <= 0 && hidden_links > 0 &&
- LYHiddenLinks != HIDDENLINKS_SEPARATE) {
+ LYHiddenLinks != HIDDENLINKS_SEPARATE
+#ifdef EXP_HEADINGLIST
+ && pounds <= 0
+#endif
+ ) {
HTUserMsg(NO_VISIBLE_REFS_FROM_DOC);
return (-1);
}
- if (refs <= 0 && hidden_links <= 0) {
+ if (refs <= 0 && hidden_links <= 0
+#ifdef EXP_HEADINGLIST
+ && pounds <= 0
+#endif
+ ) {
HTUserMsg(NO_REFS_FROM_DOC);
return (-1);
}
@@ -91,10 +105,18 @@ int showlist(DocInfo *newdoc, int titles)
? Address
: gettext("this document:")));
FREE(Address);
+#ifdef EXP_HEADINGLIST
+ if (pounds)
+ fprintf(fp0, "<a href='#headings'>#%s</a><p>\n", gettext("H1-H6"));
+#endif
if (refs > 0) {
fprintf(fp0, "<%s compact>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ?
"ol" : "ul"));
- if (hidden_links > 0)
+ if (hidden_links > 0
+#ifdef EXP_HEADINGLIST
+ || pounds > 0
+#endif
+ )
fprintf(fp0, "<lh><em>%s</em>\n", gettext("Visible links:"));
}
if (hidden_links > 0) {
@@ -103,8 +125,13 @@ int showlist(DocInfo *newdoc, int titles)
}
helper = NULL; /* init */
result = 1;
+#ifdef EXP_HEADINGLIST
+ for (cnt = 0; cnt < refs; ) {
+ HTChildAnchor *child = HText_childNext(&helper);
+#else
for (cnt = 1; cnt <= refs; cnt++) {
HTChildAnchor *child = HText_childNextNumber(cnt, &helper);
+#endif
int value = HText_findAnchorNumber(helper);
HTAnchor *dest_intl = NULL;
HTAnchor *dest;
@@ -112,6 +139,24 @@ int showlist(DocInfo *newdoc, int titles)
char *address;
const char *title;
+#ifdef EXP_HEADINGLIST
+ if (child != 0 && value == 0) {
+ if (isLYNXHEADING(child->tag)) {
+ Address = HTAnchor_address((HTAnchor *) child);
+ LYEntify(&Address, TRUE);
+ fprintf(fp0, "<%s compact>",
+ ((keypad_mode == NUMBERS_AS_ARROWS) ? "ol" : "ul"));
+ fprintf(fp0,
+ "<li><a href=\"%s\" TYPE=\"internal link\">#%s</a>",
+ Address, child->tag);
+ fprintf(fp0, "</%s>\n",
+ ((keypad_mode == NUMBERS_AS_ARROWS) ? "ol" : "ul"));
+ FREE(Address);
+ }
+ continue;
+ }
+ ++cnt;
+#endif
if (child == 0) {
/*
* child should not be 0 unless form field numbering is on and cnt
@@ -214,6 +259,30 @@ int showlist(DocInfo *newdoc, int titles)
FREE(Address);
}
+#ifdef EXP_HEADINGLIST
+ if (pounds > 0) {
+ if (refs > 0 || hidden_links > 0)
+ fprintf(fp0, "\n</%s>\n\n<p>\n",
+ ((keypad_mode == NUMBERS_AS_ARROWS) ?
+ "ol" : "ul"));
+ fprintf(fp0, "<%s compact>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ?
+ "ol continue" : "ul"));
+ fprintf(fp0, "<lh id=\"headings\"><em>%s</em>\n", gettext("H1-H6:"));
+ }
+
+ helper = NULL; /* init */
+ for (cnt = 0; cnt < pounds; cnt++) {
+ int linenum = 0;
+ HTChildAnchor *child = HText_PoundNext(TRUE, &linenum, &helper);
+ Address = HTAnchor_address((HTAnchor *) child);
+ LYEntify(&Address, TRUE);
+ fprintf(fp0,
+ "<li><a href=\"%s\" TYPE=\"internal link\">#%s</a> (line %d)\n",
+ Address, child->tag, linenum);
+ FREE(Address);
+ }
+#endif /* EXP_HEADINGLIST */
+
fprintf(fp0, "\n</%s>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ?
"ol" : "ul"));
EndInternalPage(fp0);
diff --git a/src/LYUtils.h b/src/LYUtils.h
index d15a816..8ae3749 100644
--- a/src/LYUtils.h
+++ b/src/LYUtils.h
@@ -532,6 +532,13 @@ extern "C" {
!strncasecomp(addr, STR_LYNXPROG, LEN_LYNXPROG))
#define LYNXOPTIONS_PAGE(s) STR_LYNXOPTIONS s
+
+/* internal fragment identifiers after '#' */
+#ifdef EXP_HEADINGLIST
+#define STR_LYNXHEADING ":~:LYNXHEADING_"
+#define LEN_LYNXHEADING 15
+#define isLYNXHEADING(tag) !strncasecomp(tag, STR_LYNXHEADING, LEN_LYNXHEADING)
+#endif
/*
* For change_sug_filename().
*/
diff --git a/userdefs.h b/userdefs.h
index 4fe7937..b3d2fcb 100644
--- a/userdefs.h
+++ b/userdefs.h
@@ -1684,6 +1684,11 @@
*/
#define EXP_PPRE
+/**************************
+ * Add H1-H6 heading links to ADDRLIST and LIST pages
+ */
+#define EXP_HEADINGLIST
+
/****************************************************************
* Section 4. Things you MUST check only if you plan to use Lynx
* in an anonymous account (allow public access to Lynx).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment