mirror of
https://github.com/rkd77/elinks.git
synced 2024-12-04 14:46:47 -05:00
[gemini] text/gemini
This commit is contained in:
parent
319d661541
commit
5ed65c8733
@ -4,7 +4,7 @@ include $(top_builddir)/Makefile.config
|
||||
SUBDIRS-$(CONFIG_CSS) += css
|
||||
SUBDIRS-$(CONFIG_DOM) += dom
|
||||
|
||||
SUBDIRS = html plain
|
||||
SUBDIRS = gemini html plain
|
||||
|
||||
OBJS = docdata.o document.o format.o forms.o options.o refresh.o renderer.o
|
||||
|
||||
|
6
src/document/gemini/Makefile
Normal file
6
src/document/gemini/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
top_builddir=../../..
|
||||
include $(top_builddir)/Makefile.config
|
||||
|
||||
OBJS = renderer.o
|
||||
|
||||
include $(top_srcdir)/Makefile.lib
|
1
src/document/gemini/meson.build
Normal file
1
src/document/gemini/meson.build
Normal file
@ -0,0 +1 @@
|
||||
srcs += files('renderer.c')
|
212
src/document/gemini/renderer.c
Normal file
212
src/document/gemini/renderer.c
Normal file
@ -0,0 +1,212 @@
|
||||
/* Plain text document renderer */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "elinks.h"
|
||||
|
||||
#include "bookmarks/bookmarks.h"
|
||||
#include "cache/cache.h"
|
||||
#include "config/options.h"
|
||||
#include "document/docdata.h"
|
||||
#include "document/document.h"
|
||||
#include "document/format.h"
|
||||
#include "document/options.h"
|
||||
#include "document/gemini/renderer.h"
|
||||
#include "document/html/renderer.h"
|
||||
#include "document/renderer.h"
|
||||
#include "globhist/globhist.h"
|
||||
#include "intl/charsets.h"
|
||||
#include "protocol/protocol.h"
|
||||
#include "protocol/uri.h"
|
||||
#include "terminal/color.h"
|
||||
#include "terminal/draw.h"
|
||||
#include "util/color.h"
|
||||
#include "util/error.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/string.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static void
|
||||
convert_single_line(struct string *ret, struct string *line)
|
||||
{
|
||||
if (line->length >= 4 && !strncmp(line->source, "### ", 4)) {
|
||||
add_to_string(ret, "<h3>");
|
||||
add_bytes_to_string(ret, line->source + 4, line->length - 4);
|
||||
add_to_string(ret, "</h3>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (line->length >= 3 && !strncmp(line->source, "## ", 3)) {
|
||||
add_to_string(ret, "<h2>");
|
||||
add_bytes_to_string(ret, line->source + 3, line->length - 3);
|
||||
add_to_string(ret, "</h2>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (line->length >= 2 && !strncmp(line->source, "# ", 2)) {
|
||||
add_to_string(ret, "<h1>");
|
||||
add_bytes_to_string(ret, line->source + 2, line->length - 2);
|
||||
add_to_string(ret, "</h1>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (line->length >= 2 && !strncmp(line->source, "* ", 2)) {
|
||||
add_to_string(ret, "<li>");
|
||||
add_bytes_to_string(ret, line->source + 2, line->length - 2);
|
||||
add_to_string(ret, "</li>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (line->length >= 2 && !strncmp(line->source, "> ", 2)) {
|
||||
add_to_string(ret, "<blockquote>");
|
||||
add_bytes_to_string(ret, line->source + 2, line->length - 2);
|
||||
add_to_string(ret, "</blockquote>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (line->length >= 2 && !strncmp(line->source, "=>", 2)) {
|
||||
int i = 2;
|
||||
int begin;
|
||||
add_to_string(ret, "<a href=\"");
|
||||
for (; i < line->length; ++i) {
|
||||
if (line->source[i] != ' ' && line->source[i] != '\t') {
|
||||
break;
|
||||
};
|
||||
}
|
||||
begin = i;
|
||||
|
||||
for (; i < line->length; ++i) {
|
||||
if (line->source[i] == ' ' || line->source[i] == '\t') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
add_bytes_to_string(ret, line->source + begin, i - begin);
|
||||
add_to_string(ret, "\">");
|
||||
|
||||
for (; i < line->length; ++i) {
|
||||
if (line->source[i] != ' ' && line->source[i] != '\t') {
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
add_bytes_to_string(ret, line->source + i, line->length - i);
|
||||
add_to_string(ret, "</a>");
|
||||
return;
|
||||
}
|
||||
|
||||
add_string_to_string(ret, line);
|
||||
add_to_string(ret, "<br/>");
|
||||
}
|
||||
/*
|
||||
r"^# (.*)": "h1",
|
||||
r"^## (.*)": "h2",
|
||||
r"^### (.*)": "h3",
|
||||
r"^\* (.*)": "li",
|
||||
r"^> (.*)": "blockquote",
|
||||
r"^=>\s*(\S+)(\s+.*)?": "a"
|
||||
*/
|
||||
/*
|
||||
def convert_single_line(gmi_line):
|
||||
for pattern in tags_dict.keys():
|
||||
if match := re.match(pattern, gmi_line):
|
||||
tag = tags_dict[pattern]
|
||||
groups = match.groups()
|
||||
if tag == "a":
|
||||
href = groups[0]
|
||||
inner_text = groups[1].strip() if len(groups) > 1 else href
|
||||
return f"<{tag} href='{href}'>{inner_text}</{tag}>"
|
||||
else:
|
||||
inner_text = groups[0].strip()
|
||||
return f"<{tag}>{inner_text}</{tag}>"
|
||||
return f"<p>{gmi_line}</p>"
|
||||
*/
|
||||
|
||||
void
|
||||
render_gemini_document(struct cache_entry *cached, struct document *document,
|
||||
struct string *buffer)
|
||||
{
|
||||
int preformat = 0;
|
||||
int in_list = 0;
|
||||
int i = 0;
|
||||
int begin = 0;
|
||||
struct string pre_start = INIT_STRING("<pre>", 5);
|
||||
struct string pre_end = INIT_STRING("</pre>", 6);
|
||||
struct string gem_pre = INIT_STRING("```", 3);
|
||||
struct string html;
|
||||
char *uristring;
|
||||
|
||||
char *head = empty_string_or_(cached->head);
|
||||
|
||||
(void)get_convert_table(head, document->options.cp,
|
||||
document->options.assume_cp,
|
||||
&document->cp,
|
||||
&document->cp_status,
|
||||
document->options.hard_assume);
|
||||
|
||||
init_string(&html);
|
||||
uristring = get_uri_string(document->uri, URI_PUBLIC);
|
||||
|
||||
add_to_string(&html, "<html><head><meta charset=\"utf-8\"/><base href=\"");
|
||||
add_to_string(&html, uristring);
|
||||
add_to_string(&html, "\"/></head><body>");
|
||||
mem_free_if(uristring);
|
||||
|
||||
while ( i < buffer->length) {
|
||||
|
||||
for (i = begin; i < buffer->length; ++i) {
|
||||
if (buffer->source[i] == 13 || buffer->source[i] == 10) break;
|
||||
}
|
||||
|
||||
if (begin < i) {
|
||||
int len = i - begin;
|
||||
|
||||
struct string line;
|
||||
line.source = buffer->source + begin;
|
||||
line.length = len;
|
||||
struct string *repl;
|
||||
|
||||
if (len >= 3 && (line.source[0] == '`' && line.source[1] == '`' && line.source[2] == '`')
|
||||
|| (line.source[len-1] == '`' && line.source[len-2] == '`' && line.source[len-3])) {
|
||||
preformat = !preformat;
|
||||
repl = preformat ? &pre_start : &pre_end;
|
||||
string_replace(&html, &line, &gem_pre, repl);
|
||||
} else if (preformat) {
|
||||
add_string_to_string(&html, &line);
|
||||
} else {
|
||||
struct string html_line;
|
||||
|
||||
init_string(&html_line);
|
||||
convert_single_line(&html_line, &line);
|
||||
|
||||
if (html_line.length >= 4
|
||||
&& !strcmp(html_line.source, "<li>")) {
|
||||
if (!in_list) {
|
||||
in_list = 1;
|
||||
add_to_string(&html, "<ul>\n");
|
||||
add_string_to_string(&html, &html_line);
|
||||
}
|
||||
} else if (in_list) {
|
||||
in_list = 0;
|
||||
add_to_string(&html, "</ul>\n");
|
||||
add_string_to_string(&html, &html_line);
|
||||
} else {
|
||||
add_string_to_string(&html, &html_line);
|
||||
}
|
||||
done_string(&html_line);
|
||||
}
|
||||
}
|
||||
begin = i + 1;
|
||||
add_to_string(&html, "\n");
|
||||
}
|
||||
add_to_string(&html, "</body></html>");
|
||||
|
||||
render_html_document(cached, document, &html);
|
||||
}
|
18
src/document/gemini/renderer.h
Normal file
18
src/document/gemini/renderer.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef EL__DOCUMENT_GEMINI_RENDERER_H
|
||||
#define EL__DOCUMENT_GEMINI_RENDERER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct cache_entry;
|
||||
struct document;
|
||||
struct string;
|
||||
|
||||
void render_gemini_document(struct cache_entry *cached, struct document *document, struct string *buffer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -4,6 +4,7 @@ endif
|
||||
if conf_data.get('CONFIG_DOM')
|
||||
subdir('dom')
|
||||
endif
|
||||
subdir('gemini')
|
||||
subdir('html')
|
||||
subdir('plain')
|
||||
if conf_data.get('CONFIG_XML')
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "config/options.h"
|
||||
#include "document/document.h"
|
||||
#include "document/dom/renderer.h"
|
||||
#include "document/gemini/renderer.h"
|
||||
#include "document/html/frames.h"
|
||||
#include "document/html/renderer.h"
|
||||
#include "document/plain/renderer.h"
|
||||
@ -282,6 +283,10 @@ render_encoded_document(struct cache_entry *cached, struct document *document)
|
||||
render_dom_document(cached, document, &buffer);
|
||||
else
|
||||
#endif
|
||||
if (cached->content_type
|
||||
&& (!c_strlcasecmp("text/gemini", 11, cached->content_type, -1)))
|
||||
render_gemini_document(cached, document, &buffer);
|
||||
else
|
||||
#ifdef CONFIG_XML
|
||||
if (true) render_xhtml_document(cached, document, NULL);
|
||||
else
|
||||
|
@ -1135,64 +1135,6 @@ document_writeln(JSContext *ctx, unsigned int argc, JS::Value *rval)
|
||||
return document_write_do(ctx, argc, rval, 1);
|
||||
}
|
||||
|
||||
void
|
||||
string_replace(struct string *res, struct string *inp, struct string *what, struct string *repl)
|
||||
{
|
||||
struct string tmp;
|
||||
struct string tmp2;
|
||||
char *head;
|
||||
char *found;
|
||||
char *ins;
|
||||
char *tmp_cnt;
|
||||
|
||||
init_string(&tmp);
|
||||
init_string(&tmp2);
|
||||
|
||||
add_string_to_string(&tmp, inp);
|
||||
|
||||
head = tmp.source;
|
||||
int count = 0;
|
||||
ins = head;
|
||||
if (what->length==0)
|
||||
{
|
||||
add_string_to_string(res, inp);
|
||||
return;
|
||||
}
|
||||
|
||||
// count occurence of string in input
|
||||
for (count = 0; tmp_cnt = strstr(ins, what->source); ++count)
|
||||
{
|
||||
ins = tmp_cnt + what->length;
|
||||
}
|
||||
|
||||
for (int i=0;i<count;i++) {
|
||||
// find occurence of string
|
||||
found=strstr(head,what->source);
|
||||
// count chars before and after occurence
|
||||
int bf_len=found-tmp.source;
|
||||
int af_len=tmp.length-bf_len-what->length;
|
||||
// move head by what
|
||||
found+=what->length;
|
||||
// join the before, needle and after to res
|
||||
add_bytes_to_string(&tmp2,tmp.source,bf_len);
|
||||
add_bytes_to_string(&tmp2,repl->source,repl->length);
|
||||
add_bytes_to_string(&tmp2,found,af_len);
|
||||
// clear tmp string and tmp2 string
|
||||
done_string(&tmp);
|
||||
init_string(&tmp);
|
||||
add_string_to_string(&tmp, &tmp2);
|
||||
done_string(&tmp2);
|
||||
init_string(&tmp2);
|
||||
//printf("TMP: %s |\n",tmp.source);
|
||||
head = tmp.source;
|
||||
}
|
||||
add_string_to_string(res, &tmp);
|
||||
|
||||
done_string(&tmp);
|
||||
done_string(&tmp2);
|
||||
|
||||
}
|
||||
|
||||
/* @document_funcs{"replace"} */
|
||||
static bool
|
||||
document_replace(JSContext *ctx, unsigned int argc, JS::Value *vp)
|
||||
|
@ -98,6 +98,7 @@ static union option_info default_mime_options[] = {
|
||||
INIT_OPT_MIME_EXTENSION("txt", "text/plain"),
|
||||
INIT_OPT_MIME_EXTENSION("htm", "text/html"),
|
||||
INIT_OPT_MIME_EXTENSION("html", "text/html"),
|
||||
INIT_OPT_MIME_EXTENSION("gmi", "text/gemini"),
|
||||
#ifdef CONFIG_BITTORRENT
|
||||
INIT_OPT_MIME_EXTENSION("torrent", "application/x-bittorrent"),
|
||||
#endif
|
||||
|
@ -1714,6 +1714,7 @@ struct {
|
||||
} static const known_types[] = {
|
||||
{ "text/html", 0 },
|
||||
{ "text/plain", 1 },
|
||||
{ "text/gemini", 0 },
|
||||
{ "application/xhtml+xml", 0 }, /* RFC 3236 */
|
||||
#if CONFIG_DOM
|
||||
{ "application/docbook+xml", 1 },
|
||||
|
@ -544,6 +544,63 @@ add_format_to_string(struct string *string, const char *format, ...)
|
||||
return string;
|
||||
}
|
||||
|
||||
void
|
||||
string_replace(struct string *res, struct string *inp, struct string *what, struct string *repl)
|
||||
{
|
||||
struct string tmp;
|
||||
struct string tmp2;
|
||||
char *head;
|
||||
char *found;
|
||||
char *ins;
|
||||
char *tmp_cnt;
|
||||
|
||||
init_string(&tmp);
|
||||
init_string(&tmp2);
|
||||
|
||||
add_string_to_string(&tmp, inp);
|
||||
|
||||
head = tmp.source;
|
||||
int count = 0;
|
||||
ins = head;
|
||||
if (what->length==0)
|
||||
{
|
||||
add_string_to_string(res, inp);
|
||||
return;
|
||||
}
|
||||
|
||||
// count occurence of string in input
|
||||
for (count = 0; tmp_cnt = strstr(ins, what->source); ++count)
|
||||
{
|
||||
ins = tmp_cnt + what->length;
|
||||
}
|
||||
|
||||
for (int i=0;i<count;i++) {
|
||||
// find occurence of string
|
||||
found=strstr(head,what->source);
|
||||
// count chars before and after occurence
|
||||
int bf_len=found-tmp.source;
|
||||
int af_len=tmp.length-bf_len-what->length;
|
||||
// move head by what
|
||||
found+=what->length;
|
||||
// join the before, needle and after to res
|
||||
add_bytes_to_string(&tmp2,tmp.source,bf_len);
|
||||
add_bytes_to_string(&tmp2,repl->source,repl->length);
|
||||
add_bytes_to_string(&tmp2,found,af_len);
|
||||
// clear tmp string and tmp2 string
|
||||
done_string(&tmp);
|
||||
init_string(&tmp);
|
||||
add_string_to_string(&tmp, &tmp2);
|
||||
done_string(&tmp2);
|
||||
init_string(&tmp2);
|
||||
//printf("TMP: %s |\n",tmp.source);
|
||||
head = tmp.source;
|
||||
}
|
||||
add_string_to_string(res, &tmp);
|
||||
|
||||
done_string(&tmp);
|
||||
done_string(&tmp2);
|
||||
}
|
||||
|
||||
struct string *
|
||||
add_to_string_list(LIST_OF(struct string_list_item) *list,
|
||||
const char *source, int length)
|
||||
|
@ -294,6 +294,8 @@ add_to_string_list(LIST_OF(struct string_list_item) *list,
|
||||
|
||||
void free_string_list(LIST_OF(struct string_list_item) *list);
|
||||
|
||||
void string_replace(struct string *res, struct string *inp, struct string *what, struct string *repl);
|
||||
|
||||
|
||||
/** Returns an empty C string or @a str if different from NULL. */
|
||||
#define empty_string_or_(str) ((str) ? (char *) (str) : (char *) "")
|
||||
|
Loading…
Reference in New Issue
Block a user