Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added nolinks flag to skip links during rendering #80

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions fuzzing/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ set(HEADERS
../src/html_blocks.h
../src/html_entities.h
../src/markdown.h
../src/stack.h
../src/stack.h
../src/renderers.h
)
set(LIBRARY_SOURCES
../html/houdini_href_e.c
Expand All @@ -18,7 +19,8 @@ set(LIBRARY_SOURCES
../src/autolink.c
../src/buffer.c
../src/markdown.c
../src/stack.c
../src/stack.c
../src/renderers.c
${HEADERS}
)

Expand Down
112 changes: 2 additions & 110 deletions fuzzing/snudown-validator.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "markdown.h"
#include "html.h"
#include "buffer.h"
#include "../snudown.h"

#include <ctype.h>
#include <errno.h>
Expand All @@ -19,116 +20,6 @@

#define SNUDOWN_VERSION "1.3.2"

enum snudown_renderer_mode {
RENDERER_USERTEXT = 0,
RENDERER_WIKI,
RENDERER_COUNT
};

struct snudown_renderopt {
struct html_renderopt html;
int nofollow;
const char *target;
};

struct snudown_renderer {
struct sd_markdown* main_renderer;
struct sd_markdown* toc_renderer;
struct module_state* state;
struct module_state* toc_state;
};

struct module_state {
struct sd_callbacks callbacks;
struct snudown_renderopt options;
};

static struct snudown_renderer sundown[RENDERER_COUNT];

static char* html_element_whitelist[] = {"tr", "th", "td", "table", "tbody", "thead", "tfoot", "caption", NULL};
static char* html_attr_whitelist[] = {"colspan", "rowspan", "cellspacing", "cellpadding", "scope", NULL};

static struct module_state usertext_toc_state;
static struct module_state wiki_toc_state;
static struct module_state usertext_state;
static struct module_state wiki_state;

static const unsigned int snudown_default_md_flags =
MKDEXT_NO_INTRA_EMPHASIS |
MKDEXT_SUPERSCRIPT |
MKDEXT_AUTOLINK |
MKDEXT_STRIKETHROUGH |
MKDEXT_TABLES;

static const unsigned int snudown_default_render_flags =
HTML_SKIP_HTML |
HTML_SKIP_IMAGES |
HTML_SAFELINK |
HTML_ESCAPE |
HTML_USE_XHTML;

static const unsigned int snudown_wiki_render_flags =
HTML_SKIP_HTML |
HTML_SAFELINK |
HTML_ALLOW_ELEMENT_WHITELIST |
HTML_ESCAPE |
HTML_USE_XHTML;

static void
snudown_link_attr(struct buf *ob, const struct buf *link, void *opaque)
{
struct snudown_renderopt *options = opaque;

if (options->nofollow)
BUFPUTSL(ob, " rel=\"nofollow\"");

if (options->target != NULL) {
BUFPUTSL(ob, " target=\"");
bufputs(ob, options->target);
bufputc(ob, '\"');
}
}

static struct sd_markdown* make_custom_renderer(struct module_state* state,
const unsigned int renderflags,
const unsigned int markdownflags,
int toc_renderer) {
if(toc_renderer) {
sdhtml_toc_renderer(&state->callbacks,
(struct html_renderopt *)&state->options);
} else {
sdhtml_renderer(&state->callbacks,
(struct html_renderopt *)&state->options,
renderflags);
}

state->options.html.link_attributes = &snudown_link_attr;
state->options.html.html_element_whitelist = html_element_whitelist;
state->options.html.html_attr_whitelist = html_attr_whitelist;

return sd_markdown_new(
markdownflags,
16,
64,
&state->callbacks,
&state->options
);
}

void init_default_renderer() {
sundown[RENDERER_USERTEXT].main_renderer = make_custom_renderer(&usertext_state, snudown_default_render_flags, snudown_default_md_flags, 0);
sundown[RENDERER_USERTEXT].toc_renderer = make_custom_renderer(&usertext_toc_state, snudown_default_render_flags, snudown_default_md_flags, 1);
sundown[RENDERER_USERTEXT].state = &usertext_state;
sundown[RENDERER_USERTEXT].toc_state = &usertext_toc_state;
}

void init_wiki_renderer() {
sundown[RENDERER_WIKI].main_renderer = make_custom_renderer(&wiki_state, snudown_wiki_render_flags, snudown_default_md_flags, 0);
sundown[RENDERER_WIKI].toc_renderer = make_custom_renderer(&wiki_toc_state, snudown_wiki_render_flags, snudown_default_md_flags, 1);
sundown[RENDERER_WIKI].state = &wiki_state;
sundown[RENDERER_WIKI].toc_state = &wiki_toc_state;
}

void
snudown_md(struct buf *ob, const uint8_t *document, size_t doc_size, int wiki_mode)
{
Expand Down Expand Up @@ -172,6 +63,7 @@ main(int argc, char **argv)
{
init_default_renderer();
init_wiki_renderer();
init_default_renderer_without_links();

struct buf *ib, *ob;
int size_read = 0, wiki_mode = 0, i = 0, have_errors = 0;
Expand Down
130 changes: 20 additions & 110 deletions snudown.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,125 +2,34 @@
#include <Python.h>

#include "markdown.h"
#include "html.h"
#include "autolink.h"
#include "renderers.h"
#include "snudown.h"

#define SNUDOWN_VERSION "1.4.0"

enum snudown_renderer_mode {
RENDERER_USERTEXT = 0,
RENDERER_WIKI,
RENDERER_COUNT
};

struct snudown_renderopt {
struct html_renderopt html;
int nofollow;
const char *target;
};

struct snudown_renderer {
struct sd_markdown* main_renderer;
struct sd_markdown* toc_renderer;
struct module_state* state;
struct module_state* toc_state;
};

struct module_state {
struct sd_callbacks callbacks;
struct snudown_renderopt options;
};

static struct snudown_renderer sundown[RENDERER_COUNT];

static char* html_element_whitelist[] = {"tr", "th", "td", "table", "tbody", "thead", "tfoot", "caption", NULL};
static char* html_attr_whitelist[] = {"colspan", "rowspan", "cellspacing", "cellpadding", "scope", NULL};

static struct module_state usertext_toc_state;
static struct module_state wiki_toc_state;
static struct module_state usertext_state;
static struct module_state wiki_state;
#define SNUDOWN_VERSION "1.5.0"

/* The module doc strings */
PyDoc_STRVAR(snudown_module__doc__, "When does the narwhal bacon? At Sundown.");
PyDoc_STRVAR(snudown_md__doc__, "Render a Markdown document");

static const unsigned int snudown_default_md_flags =
MKDEXT_NO_INTRA_EMPHASIS |
MKDEXT_SUPERSCRIPT |
MKDEXT_AUTOLINK |
MKDEXT_STRIKETHROUGH |
MKDEXT_TABLES;

static const unsigned int snudown_default_render_flags =
HTML_SKIP_HTML |
HTML_SKIP_IMAGES |
HTML_SAFELINK |
HTML_ESCAPE |
HTML_USE_XHTML;

static const unsigned int snudown_wiki_render_flags =
HTML_SKIP_HTML |
HTML_SAFELINK |
HTML_ALLOW_ELEMENT_WHITELIST |
HTML_ESCAPE |
HTML_USE_XHTML;

static void
snudown_link_attr(struct buf *ob, const struct buf *link, void *opaque)
{
struct snudown_renderopt *options = opaque;

if (options->nofollow)
BUFPUTSL(ob, " rel=\"nofollow\"");

if (options->target != NULL) {
BUFPUTSL(ob, " target=\"");
bufputs(ob, options->target);
bufputc(ob, '\"');
}
}

static struct sd_markdown* make_custom_renderer(struct module_state* state,
const unsigned int renderflags,
const unsigned int markdownflags,
int toc_renderer) {
if(toc_renderer) {
sdhtml_toc_renderer(&state->callbacks,
(struct html_renderopt *)&state->options);
} else {
sdhtml_renderer(&state->callbacks,
(struct html_renderopt *)&state->options,
renderflags);
}

state->options.html.link_attributes = &snudown_link_attr;
state->options.html.html_element_whitelist = html_element_whitelist;
state->options.html.html_attr_whitelist = html_attr_whitelist;

return sd_markdown_new(
markdownflags,
16,
64,
&state->callbacks,
&state->options
);
}
static struct snudown_renderer sundown[RENDERER_COUNT];

void init_default_renderer(PyObject *module) {
void register_default_renderer(PyObject *module) {
PyModule_AddIntConstant(module, "RENDERER_USERTEXT", RENDERER_USERTEXT);
sundown[RENDERER_USERTEXT].main_renderer = make_custom_renderer(&usertext_state, snudown_default_render_flags, snudown_default_md_flags, 0);
sundown[RENDERER_USERTEXT].toc_renderer = make_custom_renderer(&usertext_toc_state, snudown_default_render_flags, snudown_default_md_flags, 1);
sundown[RENDERER_USERTEXT].state = &usertext_state;
sundown[RENDERER_USERTEXT].toc_state = &usertext_toc_state;
struct snudown_renderer *renderer = get_default_renderer();
sundown[RENDERER_USERTEXT] = *renderer;
}

void init_wiki_renderer(PyObject *module) {
void register_wiki_renderer(PyObject *module) {
PyModule_AddIntConstant(module, "RENDERER_WIKI", RENDERER_WIKI);
sundown[RENDERER_WIKI].main_renderer = make_custom_renderer(&wiki_state, snudown_wiki_render_flags, snudown_default_md_flags, 0);
sundown[RENDERER_WIKI].toc_renderer = make_custom_renderer(&wiki_toc_state, snudown_wiki_render_flags, snudown_default_md_flags, 1);
sundown[RENDERER_WIKI].state = &wiki_state;
sundown[RENDERER_WIKI].toc_state = &wiki_toc_state;
struct snudown_renderer *renderer = get_wiki_renderer();
sundown[RENDERER_WIKI] = *renderer;
}

void register_default_renderer_without_links(PyObject *module) {
PyModule_AddIntConstant(module, "RENDERER_USERTEXT_WITHOUTLINKS", RENDERER_USERTEXT_WITHOUTLINKS);
struct snudown_renderer *renderer = get_default_renderer_without_links();
sundown[RENDERER_USERTEXT_WITHOUTLINKS] = *renderer;
}

static PyObject *
Expand Down Expand Up @@ -204,9 +113,10 @@ PyMODINIT_FUNC initsnudown(void)
if (module == NULL)
return;

init_default_renderer(module);
init_wiki_renderer(module);
register_default_renderer(module);
register_wiki_renderer(module);
register_default_renderer_without_links(module);

/* Version */
PyModule_AddStringConstant(module, "__version__", SNUDOWN_VERSION);
}
}
5 changes: 2 additions & 3 deletions src/markdown.c
Original file line number Diff line number Diff line change
Expand Up @@ -2530,16 +2530,15 @@ sd_markdown_new(
if (md->cb.linebreak)
md->active_char['\n'] = MD_CHAR_LINEBREAK;

if (md->cb.image || md->cb.link)
md->active_char['['] = MD_CHAR_LINK;

md->active_char['<'] = MD_CHAR_LANGLE;
md->active_char['\\'] = MD_CHAR_ESCAPE;
md->active_char['&'] = MD_CHAR_ENTITITY;

if (extensions & MKDEXT_AUTOLINK) {
if (!(extensions & MKDEXT_NO_EMAIL_AUTOLINK))
md->active_char['@'] = MD_CHAR_AUTOLINK_EMAIL;
if (md->cb.image || md->cb.link)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change confuses me.

[text](http://url) isn't an automatic link, it's an explicit one the user wrote out, so why would the MKDEXT_AUTOLINK flag affect how that syntax is rendered?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. We also don't want to skip by the link structure entirely, we just want to not render the link. Outputting [foo](/bar) verbatim probably isn't the way to go either.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that it confuses, but I tried to avoid situations when user is mentioned my direct, without investing much effort. I'll revert this part, so link will be rendered as expected

md->active_char['['] = MD_CHAR_LINK;
md->active_char[':'] = MD_CHAR_AUTOLINK_URL;
md->active_char['w'] = MD_CHAR_AUTOLINK_WWW;
md->active_char['/'] = MD_CHAR_AUTOLINK_SUBREDDIT_OR_USERNAME;
Expand Down
Loading