Last active
May 29, 2022 01:35
-
-
Save deton/ebc9d4b4af6c216bd49cdb656a9b0ebc to your computer and use it in GitHub Desktop.
lynx patch for <p> style white-space:pre
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/WWW/Library/Implementation/HTStyle.h b/WWW/Library/Implementation/HTStyle.h | |
index 79ba003..efaeaed 100644 | |
--- a/WWW/Library/Implementation/HTStyle.h | |
+++ b/WWW/Library/Implementation/HTStyle.h | |
@@ -221,6 +221,8 @@ extern "C" { | |
ST_GlossaryCompact6, | |
ST_Example, | |
ST_Preformatted, | |
+ ST_PreformattedDiv, | |
+ ST_PreformattedP, | |
ST_Listing, | |
ST_Address, | |
ST_Note, | |
diff --git a/lynx.cfg b/lynx.cfg | |
index b6224f1..9ba4dd2 100644 | |
--- a/lynx.cfg | |
+++ b/lynx.cfg | |
@@ -3034,6 +3034,14 @@ COLOR:6:brightred:black | |
#COLOR_STYLE: mild-colors.lss | |
#COLOR_STYLE: opaque.lss | |
+.h2 PARAGRAPH_STYLE | |
+# Pre-format <P> or <DIV> class names feature | |
+# for <p class="xxx"> or <div class="xxx"> with CSS ".xxx{white-space:pre}". | |
+# PARAGRAPH_STYLE:ppre <url> .<classname>[,.<classname>]* | |
+.ex 2 | |
+# PARAGRAPH_STYLE:ppre https://nitter.net .media-body,.quote-text | |
+# PARAGRAPH_STYLE:ppre https://togetter.com .tweet | |
+ | |
.h2 NESTED_TABLES | |
# This is an experimental feature for improving table layout. | |
# It is enabled by default when the COLOR_STYLE configuration is used, | |
diff --git a/src/DefaultStyle.c b/src/DefaultStyle.c | |
index 3dc17f7..ebb5a46 100644 | |
--- a/src/DefaultStyle.c | |
+++ b/src/DefaultStyle.c | |
@@ -346,9 +346,27 @@ HTStyleInit( | |
NO, NO, 0, 0, 0 | |
); | |
+static HTStyle HTStylePreformattedDiv = | |
+HTStyleInit( /* <div style="white-space: pre;"> */ | |
+ &HTStylePreformatted, | |
+ PreformattedDiv, "DIVPRE", | |
+ HT_FONT, 1, HT_BLACK, 0, 0, | |
+ 3, 3, 6, HT_LEFT, 1, 0, tabs_8, | |
+ YES, NO, 0, 0, 0 | |
+); | |
+ | |
+static HTStyle HTStylePreformattedP = | |
+HTStyleInit( /* <p style="white-space: pre;"> */ | |
+ &HTStylePreformattedDiv, | |
+ PreformattedP, "PPRE", | |
+ HT_FONT, 1, HT_BLACK, 0, 0, | |
+ 3, 3, 6, HT_LEFT, 1, 0, tabs_8, | |
+ YES, NO, 0, 0, 0 | |
+); | |
+ | |
static HTStyle HTStyleListing = | |
HTStyleInit( | |
- &HTStylePreformatted, Listing, "LISTING", | |
+ &HTStylePreformattedP, Listing, "LISTING", | |
HT_FONT, 1, HT_BLACK, 0, 0, | |
0, 0, 0, HT_LEFT, 1, 0, tabs_8, | |
NO, NO, 0, 0, 0); | |
diff --git a/src/HTML.c b/src/HTML.c | |
index cf2e18b..9121881 100644 | |
--- a/src/HTML.c | |
+++ b/src/HTML.c | |
@@ -62,10 +62,12 @@ | |
#include <SGML.h> | |
#include <AttrList.h> | |
#include <LYHash.h> | |
+#endif /* USE_COLOR_STYLE */ | |
+#if defined(USE_COLOR_STYLE) || defined(EXP_PPRE) | |
#include <LYStyle.h> | |
#undef SELECTED_STYLES | |
#define pHText_changeStyle(X,Y,Z) {} | |
-#endif /* USE_COLOR_STYLE */ | |
+#endif | |
#ifdef USE_SOURCE_CACHE | |
#include <HTAccess.h> | |
@@ -112,7 +114,7 @@ static HTStyleSheet *styleSheet = NULL; /* Application-wide */ | |
/* Module-wide style cache | |
*/ | |
-static HTStyle *styles[HTML_ELEMENTS + LYNX_HTML_EXTRA_ELEMENTS]; | |
+static HTStyle *styles[HTML_ELEMENTS + LYNX_HTML_EXTRA_ELEMENTS + 1]; | |
/* adding 24 nested list styles */ | |
/* and 3 header alignment styles */ | |
@@ -429,7 +431,12 @@ void HTML_put_character(HTStructured * me, int c) | |
/* | |
* Free format text. | |
*/ | |
- if (me->sp->style->id == ST_Preformatted) { | |
+ if (me->sp->style->id == ST_Preformatted | |
+#ifdef EXP_PPRE | |
+ || me->sp->style->id == ST_PreformattedP | |
+ || me->sp->style->id == ST_PreformattedDiv | |
+#endif | |
+ ) { | |
if (c != '\r' && | |
!(c == '\n' && me->inLABEL && !me->inP) && | |
!(c == '\n' && !me->inPRE)) { | |
@@ -1725,6 +1732,13 @@ static int HTML_start_element(HTStructured * me, int element_number, | |
me->sp[0].tag_number == HTML_LH || | |
me->sp[0].tag_number == HTML_DD) | |
me->current_default_alignment = HT_LEFT; | |
+#ifdef EXP_PPRE | |
+ if (present && present[HTML_DIV_CLASS] && | |
+ LYParaStyle_match(me->ppre_style, value[HTML_DIV_CLASS])) { | |
+ change_paragraph_style(me, styles[HTML_DIVPRE]); | |
+ me->current_default_alignment = styles[HTML_DIVPRE]->alignment;; | |
+ } | |
+#endif | |
LYHandlePlike(me, present, value, include, HTML_DIV_ALIGN, TRUE); | |
me->DivisionAlignments[me->Division_Level] = (short) | |
me->current_default_alignment; | |
@@ -1742,15 +1756,27 @@ static int HTML_start_element(HTStructured * me, int element_number, | |
me->current_default_alignment = styles[HTML_DRIGHT]->alignment; | |
} else { | |
me->DivisionAlignments[me->Division_Level] = HT_LEFT; | |
- change_paragraph_style(me, styles[HTML_DLEFT]); | |
+#ifdef EXP_PPRE | |
+ if (present && present[HTML_DIV_CLASS] && | |
+ LYParaStyle_match(me->ppre_style, value[HTML_DIV_CLASS])) | |
+ change_paragraph_style(me, styles[HTML_DIVPRE]); | |
+ else | |
+#endif | |
+ change_paragraph_style(me, styles[HTML_DLEFT]); | |
UPDATE_STYLE; | |
- me->current_default_alignment = styles[HTML_DLEFT]->alignment; | |
+ me->current_default_alignment = me->new_style->alignment; | |
} | |
} else { | |
me->DivisionAlignments[me->Division_Level] = HT_LEFT; | |
- change_paragraph_style(me, styles[HTML_DLEFT]); | |
+#ifdef EXP_PPRE | |
+ if (present && present[HTML_DIV_CLASS] && | |
+ LYParaStyle_match(me->ppre_style, value[HTML_DIV_CLASS])) | |
+ change_paragraph_style(me, styles[HTML_DIVPRE]); | |
+ else | |
+#endif | |
+ change_paragraph_style(me, styles[HTML_DLEFT]); | |
UPDATE_STYLE; | |
- me->current_default_alignment = styles[HTML_DLEFT]->alignment; | |
+ me->current_default_alignment = me->new_style->alignment; | |
} | |
CHECK_ID(HTML_DIV_ID); | |
break; | |
@@ -1846,6 +1872,11 @@ static int HTML_start_element(HTStructured * me, int element_number, | |
break; | |
case HTML_P: | |
+#ifdef EXP_PPRE | |
+ if (present && present[HTML_P_CLASS] && | |
+ LYParaStyle_match(me->ppre_style, value[HTML_P_CLASS])) | |
+ change_paragraph_style(me, styles[HTML_PPRE]); | |
+#endif | |
LYHandlePlike(me, present, value, include, HTML_P_ALIGN, TRUE); | |
CHECK_ID(HTML_P_ID); | |
break; | |
@@ -5293,6 +5324,10 @@ static int HTML_start_element(HTStructured * me, int element_number, | |
} else if (me->List_Nesting_Level >= 0 || | |
((me->Division_Level < 0) && | |
(me->sp->style->id == ST_Normal || | |
+#ifdef EXP_PPRE | |
+ me->sp->style->id == ST_PreformattedP || | |
+ me->sp->style->id == ST_PreformattedDiv || | |
+#endif | |
me->sp->style->id == ST_Preformatted))) { | |
me->sp->style->alignment = HT_LEFT; | |
} else { | |
@@ -5926,6 +5961,9 @@ static int HTML_end_element(HTStructured * me, int element_number, | |
break; | |
case HTML_P: | |
+#ifdef EXP_PPRE /* HTML_PPRE style end */ | |
+ change_paragraph_style(me, me->sp->style); | |
+#endif | |
LYHandlePlike(me, | |
(const BOOL *) 0, (STRING2PTR) 0, | |
include, 0, | |
@@ -7414,6 +7452,7 @@ static void get_styles(void) | |
styles[HTML_DCENTER] = st[ST_DivCenter]; | |
styles[HTML_DLEFT] = st[ST_DivLeft]; | |
styles[HTML_DRIGHT] = st[ST_DivRight]; | |
+ styles[HTML_DIVPRE] = st[ST_PreformattedDiv]; | |
styles[HTML_DL] = st[ST_Glossary]; | |
/* nested list styles */ | |
@@ -7462,6 +7501,7 @@ static void get_styles(void) | |
styles[HTML_PLAINTEXT] = | |
styles[HTML_XMP] = st[ST_Example]; | |
styles[HTML_PRE] = st[ST_Preformatted]; | |
+ styles[HTML_PPRE] = st[ST_PreformattedP]; | |
styles[HTML_LISTING] = st[ST_Listing]; | |
} | |
@@ -7590,6 +7630,9 @@ HTStructured *HTML_new(HTParentAnchor *anchor, | |
me->sp->style = default_style; /* INVALID */ | |
me->sp->style->alignment = HT_LEFT; | |
me->stack_overrun = FALSE; | |
+#ifdef EXP_PPRE | |
+ me->ppre_style = LYParaStyle_for_url(anchor->address); | |
+#endif | |
me->Division_Level = -1; | |
me->Underline_Level = 0; | |
diff --git a/src/HTML.h b/src/HTML.h | |
index 9f5d1d5..e2ea634 100644 | |
--- a/src/HTML.h | |
+++ b/src/HTML.h | |
@@ -141,6 +141,9 @@ extern "C" { | |
stack_element *sp; /* Style stack pointer */ | |
BOOL stack_overrun; /* Was MAX_NESTING exceeded? */ | |
int skip_stack; /* flag to skip next style stack operation */ | |
+#ifdef EXP_PPRE | |
+ int ppre_style; /* Pre-format <p> and <div> style index */ | |
+#endif | |
/* | |
* Track if we are in an anchor, paragraph, address, base, etc. | |
diff --git a/src/HTNestedList.h b/src/HTNestedList.h | |
index 5a5f103..7f44924 100644 | |
--- a/src/HTNestedList.h | |
+++ b/src/HTNestedList.h | |
@@ -39,6 +39,9 @@ | |
#define HTML_OBJECT_M (HTML_ELEMENTS+31) | |
-#define LYNX_HTML_EXTRA_ELEMENTS 31 | |
+#define HTML_DIVPRE (HTML_ELEMENTS+32) | |
+#define HTML_PPRE (HTML_ELEMENTS+33) | |
+ | |
+#define LYNX_HTML_EXTRA_ELEMENTS 33 | |
#endif /* HTNESTEDLIST_H */ | |
diff --git a/src/LYCharUtils.c b/src/LYCharUtils.c | |
index 0013989..03b2e81 100644 | |
--- a/src/LYCharUtils.c | |
+++ b/src/LYCharUtils.c | |
@@ -2635,6 +2635,10 @@ void LYHandlePlike(HTStructured * me, const BOOL *present, | |
me->sp->style->id == ST_DivRight)) || | |
((me->Division_Level < 0) && | |
(me->sp->style->id == ST_Normal || | |
+#ifdef EXP_PPRE | |
+ me->sp->style->id == ST_PreformattedP || | |
+ me->sp->style->id == ST_PreformattedDiv || | |
+#endif | |
me->sp->style->id == ST_Preformatted))) { | |
me->sp->style->alignment = HT_LEFT; | |
} else { | |
@@ -3213,6 +3217,10 @@ void LYResetParagraphAlignment(HTStructured * me) | |
if (me->List_Nesting_Level >= 0 || | |
((me->Division_Level < 0) && | |
(me->sp->style->id == ST_Normal || | |
+#ifdef EXP_PPRE | |
+ me->sp->style->id == ST_PreformattedP || | |
+ me->sp->style->id == ST_PreformattedDiv || | |
+#endif | |
me->sp->style->id == ST_Preformatted))) { | |
me->sp->style->alignment = HT_LEFT; | |
} else { | |
diff --git a/src/LYMain.c b/src/LYMain.c | |
index af78ef7..0c248ad 100644 | |
--- a/src/LYMain.c | |
+++ b/src/LYMain.c | |
@@ -876,6 +876,9 @@ static void free_lynx_globals(void) | |
FREE(nonoption); | |
#endif | |
LYFreeStringList(positionable_editor); | |
+#ifdef EXP_PPRE | |
+ LYParaStyle_free(); | |
+#endif | |
return; | |
} | |
diff --git a/src/LYReadCFG.c b/src/LYReadCFG.c | |
index 18bc34c..935f04c 100644 | |
--- a/src/LYReadCFG.c | |
+++ b/src/LYReadCFG.c | |
@@ -42,6 +42,10 @@ | |
#include <HTNews.h> | |
#endif | |
+#ifdef EXP_PPRE | |
+#include <LYStyle.h> | |
+#endif | |
+ | |
BOOLEAN have_read_cfg = FALSE; | |
BOOLEAN LYUseNoviceLineTwo = TRUE; | |
@@ -1659,6 +1663,9 @@ static Config_Type Config_Table [] = | |
PARSE_SET(RC_UPDATE_TERM_TITLE, update_term_title), | |
PARSE_FUN(RC_NONRESTARTING_SIGWINCH, nonrest_sigwinch_fun), | |
PARSE_FUN(RC_OUTGOING_MAIL_CHARSET, outgoing_mail_charset_fun), | |
+#ifdef EXP_PPRE | |
+ PARSE_FUN(RC_PARAGRAPH_STYLE, LYParaStyle_add), | |
+#endif | |
#ifdef DISP_PARTIAL | |
PARSE_SET(RC_PARTIAL, display_partial_flag), | |
PARSE_INT(RC_PARTIAL_THRES, partial_threshold), | |
diff --git a/src/LYStyle.c b/src/LYStyle.c | |
index 77be188..ebc8b22 100644 | |
--- a/src/LYStyle.c | |
+++ b/src/LYStyle.c | |
@@ -968,3 +968,123 @@ void reinit_color_styles(void) | |
} | |
#endif /* USE_COLOR_STYLE */ | |
+ | |
+#ifdef EXP_PPRE | |
+static HTList *paragraph_styles = NULL; | |
+ | |
+typedef struct _paragraph_style_item { | |
+ char *url; | |
+ HTList *classnames; | |
+} paragraph_style_item; | |
+ | |
+int LYParaStyle_add(char *config) | |
+{ | |
+ char *style; | |
+ char *url; | |
+ char *selector; | |
+ char *p; | |
+ HTList *classnames; | |
+ paragraph_style_item *item = NULL; | |
+ | |
+ style = HTNextField(&config); | |
+ if (!style) | |
+ return 0; | |
+ if (strcmp(style, "ppre")) { | |
+ CTRACE((tfp, "Unknown PARAGRAPH_STYLE:%s ignored.\n", style)); | |
+ return 0; | |
+ } | |
+ url = HTNextField(&config); | |
+ if (!url) | |
+ return 0; | |
+ /* '.' prefixed class names separated by comma. ".name3,.name4" */ | |
+ selector = HTNextField(&config); | |
+ if (!selector) | |
+ return 0; | |
+ classnames = HTList_new(); | |
+ while ((p = LYstrsep(&selector, ",")) != NULL) { | |
+ if (*p != '.') { | |
+ CTRACE((tfp, "Unsupported PARAGRAPH_STYLE selector:%s ignored.\n", p)); | |
+ continue; | |
+ } | |
+ p++; | |
+ if (isEmpty(p)) | |
+ continue; | |
+ char *classname = NULL; | |
+ StrAllocCopy(classname, p); | |
+ HTList_addObject(classnames, classname); | |
+ } | |
+ | |
+ if (paragraph_styles == NULL) | |
+ paragraph_styles = HTList_new(); | |
+ item = typecalloc(paragraph_style_item); | |
+ if (item == NULL) | |
+ outofmem(__FILE__, "LYParaStyle_add"); | |
+ StrAllocCopy(item->url, url); | |
+ item->classnames = classnames; | |
+ HTList_addObject(paragraph_styles, item); | |
+ return 0; | |
+} | |
+ | |
+void LYParaStyle_free() | |
+{ | |
+ paragraph_style_item *item; | |
+ HTList *cur = paragraph_styles; | |
+ | |
+ while ((item = (paragraph_style_item *) HTList_nextObject(cur)) != NULL) { | |
+ FREE(item->url); | |
+ LYFreeStringList(item->classnames); | |
+ } | |
+ HTList_delete(paragraph_styles); | |
+ paragraph_styles = NULL; | |
+} | |
+ | |
+int LYParaStyle_for_url(const char *url) | |
+{ | |
+ int pos; | |
+ paragraph_style_item *item; | |
+ HTList *cur = paragraph_styles; | |
+ | |
+ for (pos = 0; | |
+ (item = (paragraph_style_item *) HTList_nextObject(cur)) != NULL; | |
+ pos++) { | |
+ if (StrNCmp(item->url, url, strlen(item->url)) == 0) { | |
+ CTRACE((tfp, "LYParaStyle_for_url style %d for:%s\n", pos, url)); | |
+ return pos; | |
+ } | |
+ } | |
+ return -1; | |
+} | |
+ | |
+/* | |
+ * Check whether 'attr' matches class names for styleIndex. | |
+ * attr: class names separated by space. "name1 name2" | |
+ */ | |
+BOOL LYParaStyle_match(int styleIndex, const char *attr) | |
+{ | |
+ char *tmpbuf = 0; | |
+ char *anext; | |
+ char *a; | |
+ paragraph_style_item *style; | |
+ | |
+ if (styleIndex < 0 || isEmpty(attr)) | |
+ return FALSE; | |
+ style = HTList_objectAt(paragraph_styles, styleIndex); | |
+ if (style == NULL) | |
+ return FALSE; | |
+ | |
+ StrAllocCopy(tmpbuf, attr); | |
+ anext = tmpbuf; | |
+ while ((a = LYstrsep(&anext, " ")) != 0) { | |
+ char *name; | |
+ HTList *cur = style->classnames; | |
+ while ((name = (char *) HTList_nextObject(cur)) != NULL) { | |
+ if (STREQ(name, a)) { | |
+ FREE(tmpbuf); | |
+ return TRUE; | |
+ } | |
+ } | |
+ } | |
+ FREE(tmpbuf); | |
+ return FALSE; | |
+} | |
+#endif /* EXP_PPRE */ | |
diff --git a/src/LYStyle.h b/src/LYStyle.h | |
index a7e5e81..8e8da70 100644 | |
--- a/src/LYStyle.h | |
+++ b/src/LYStyle.h | |
@@ -85,4 +85,19 @@ extern "C" { | |
#endif /* USE_COLOR_STYLE */ | |
extern int lynx_has_color; | |
+#ifdef EXP_PPRE | |
+#ifdef __cplusplus | |
+extern "C" { | |
+#endif | |
+ /* Functions for paragraph style */ | |
+ extern int LYParaStyle_add(char *config); | |
+ extern void LYParaStyle_free(); | |
+ extern int LYParaStyle_for_url(const char *url); | |
+ extern BOOL LYParaStyle_match(int styleIndex, const char *attr); | |
+ | |
+#ifdef __cplusplus | |
+} | |
+#endif | |
+#endif /* EXP_PPRE */ | |
+ | |
#endif /* LYSTYLE_H */ | |
diff --git a/src/LYrcFile.h b/src/LYrcFile.h | |
index f23c87f..14c18b0 100644 | |
--- a/src/LYrcFile.h | |
+++ b/src/LYrcFile.h | |
@@ -183,6 +183,7 @@ | |
#define RC_NUMBER_FIELDS_ON_LEFT "number_fields_on_left" | |
#define RC_NUMBER_LINKS_ON_LEFT "number_links_on_left" | |
#define RC_OUTGOING_MAIL_CHARSET "outgoing_mail_charset" | |
+#define RC_PARAGRAPH_STYLE "paragraph_style" | |
#define RC_PARTIAL "partial" | |
#define RC_PARTIAL_THRES "partial_thres" | |
#define RC_PERSISTENT_COOKIES "persistent_cookies" | |
diff --git a/userdefs.h b/userdefs.h | |
index a1d370a..35f1c06 100644 | |
--- a/userdefs.h | |
+++ b/userdefs.h | |
@@ -1677,6 +1677,13 @@ | |
*/ | |
#define SSL_CERT_FILE NULL | |
+/************************** | |
+ * Pre-format <P> class names feature. | |
+ * for <p class="xxx"> or <div class="xxx"> | |
+ * with CSS ".xxx{white-space:pre}" | |
+ */ | |
+#define EXP_PPRE | |
+ | |
/**************************************************************** | |
* 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