diff --git a/README.markdown b/README.markdown index 1d491864..7700a9bc 100644 --- a/README.markdown +++ b/README.markdown @@ -134,6 +134,8 @@ The `--smart` extension provides "smart quotes", dashes, and ellipses. The `--notes` extension provides a footnote syntax like that of Pandoc or PHP Markdown Extra. +The `--autolink` extension converts bare URLs into links. + Using the library ================= @@ -160,6 +162,7 @@ bitwise `&` operator and the following constants: - `EXT_NOTES` turns on footnote syntax. [Pandoc's footnote syntax][] is used here. - `EXT_FILTER_HTML` filters out raw HTML (except for styles). - `EXT_FILTER_STYLES` filters out styles in HTML. + - `EXT_AUTOLINK` turns bare URLs into links. [Pandoc's footnote syntax]: http://johnmacfarlane.net/pandoc/README.html#footnotes diff --git a/markdown.c b/markdown.c index 8a45a593..8b4dbb20 100644 --- a/markdown.c +++ b/markdown.c @@ -71,6 +71,9 @@ int main(int argc, char * argv[]) { static gboolean opt_notes = FALSE; static gboolean opt_filter_html = FALSE; static gboolean opt_filter_styles = FALSE; + static gboolean opt_strike = FALSE; + static gboolean opt_autolink = FALSE; + static gboolean opt_hardwrap = FALSE; static gboolean opt_allext = FALSE; static GOptionEntry entries[] = @@ -87,8 +90,11 @@ int main(int argc, char * argv[]) { /* Options to active syntax extensions. These appear separately in --help. */ static GOptionEntry ext_entries[] = { - { "smart", 0, 0, G_OPTION_ARG_NONE, &opt_smart, "use smart typography extension", NULL }, - { "notes", 0, 0, G_OPTION_ARG_NONE, &opt_notes, "use notes extension", NULL }, + { "smart", 0, 0, G_OPTION_ARG_NONE, &opt_smart, "use smart typography extension", NULL }, + { "notes", 0, 0, G_OPTION_ARG_NONE, &opt_notes, "use notes extension", NULL }, + { "strike", 0, 0, G_OPTION_ARG_NONE, &opt_strike, "use strike-through extension", NULL }, + { "autolink", 0, 0, G_OPTION_ARG_NONE, &opt_autolink, "autolink bare URLs", NULL }, + { "hardwrap", 0, 0, G_OPTION_ARG_NONE, &opt_hardwrap, "respect linebreaks in paragraphs", NULL }, { NULL } }; @@ -127,6 +133,12 @@ int main(int argc, char * argv[]) { extensions = extensions | EXT_FILTER_HTML; if (opt_filter_styles) extensions = extensions | EXT_FILTER_STYLES; + if (opt_strike) + extensions = extensions | EXT_STRIKE; + if (opt_autolink) + extensions = extensions | EXT_AUTOLINK; + if (opt_hardwrap) + extensions = extensions | EXT_HARD_WRAP; if (opt_to == NULL) output_format = HTML_FORMAT; diff --git a/markdown_lib.h b/markdown_lib.h index bcd6e43c..418066f8 100644 --- a/markdown_lib.h +++ b/markdown_lib.h @@ -6,7 +6,10 @@ enum markdown_extensions { EXT_SMART = 0x01, EXT_NOTES = 0x02, EXT_FILTER_HTML = 0x04, - EXT_FILTER_STYLES = 0x08 + EXT_FILTER_STYLES = 0x08, + EXT_STRIKE = 0x10, + EXT_AUTOLINK = 0x20, + EXT_HARD_WRAP = 0x40 }; enum markdown_formats { diff --git a/markdown_output.c b/markdown_output.c index b814a4ec..ef4435e0 100644 --- a/markdown_output.c +++ b/markdown_output.c @@ -212,6 +212,11 @@ static void print_html_element(GString *out, element *elt, bool obfuscate) { print_html_element_list(out, elt->children, obfuscate); g_string_append_printf(out, ""); break; + case STRIKE: + g_string_append_printf(out, ""); + print_html_element_list(out, elt->children, obfuscate); + g_string_append_printf(out, ""); + break; case LIST: print_html_element_list(out, elt->children, obfuscate); break; diff --git a/markdown_parser.leg b/markdown_parser.leg index e1fd5d80..3b66e8d2 100644 --- a/markdown_parser.leg +++ b/markdown_parser.leg @@ -56,7 +56,7 @@ AtxInline = !Newline !(Sp? '#'* Sp Newline) Inline AtxStart = < ( "######" | "#####" | "####" | "###" | "##" | "#" ) > { $$ = mk_element(H1 + (strlen(yytext) - 1)); } -AtxHeading = s:AtxStart Sp? a:StartList ( AtxInline { a = cons($$, a); } )+ (Sp? '#'* Sp)? Newline +AtxHeading = s:AtxStart Spacechar+ a:StartList ( AtxInline { a = cons($$, a); } )+ (Sp? '#'* Sp)? Newline { $$ = mk_list(s->key, a); free(s); } @@ -383,14 +383,15 @@ Inlines = a:StartList ( !Endline Inline { a = cons($$, a); } | c:Endline &Inline { a = cons(c, a); } )+ Endline? { $$ = mk_list(LIST, a); } -Inline = Str - | Endline +Inline = Endline | UlOrStarLine | Space | Strong | Emph + | Strike | Image | Link + | Str | NoteReference | InlineNote | Code @@ -430,7 +431,7 @@ NormalEndline = Sp Newline !BlankLine !'>' !AtxStart TerminalEndline = Sp Newline Eof { $$ = NULL; } -LineBreak = " " NormalEndline +LineBreak = ( " " NormalEndline | &{ extension(EXT_HARD_WRAP) } NormalEndline ) { $$ = mk_element(LINEBREAK); } Symbol = < SpecialChar > @@ -441,6 +442,7 @@ Symbol = < SpecialChar > UlOrStarLine = (UlLine | StarLine) { $$ = mk_str(yytext); } StarLine = < "****" '*'* > | < Spacechar '*'+ &Spacechar > UlLine = < "____" '_'* > | < Spacechar '_'+ &Spacechar > +TildeLine = < "~~~~" '~'* > | < Spacechar '~'+ &Spacechar > SpaceInline = a:StartList ( (b:Space | b:Endline) { a = cons(b, a); } )+ @@ -486,6 +488,16 @@ StrongUl = "__" "__" { $$ = mk_list(STRONG, a); } +TwoTildeOpen = &{ extension(EXT_STRIKE) } !TildeLine "~~" !Spacechar !Newline +TwoTildeClose = &{ extension(EXT_STRIKE) } !Spacechar !Newline a:Inline "~~" { $$ = a; } + +Strike = &{ extension(EXT_STRIKE) } + TwoTildeOpen + a:StartList + ( !TwoTildeClose Inline { a = cons($$, a); } )* + TwoTildeClose { a = cons($$, a); } + { $$ = mk_list(STRIKE, a); } + Image = '!' ( ExplicitLink | ReferenceLink ) { if ($$->key == LINK) { $$->key = IMAGE; @@ -549,7 +561,8 @@ TitleDouble = '"' < ( !( '"' Sp ( ')' | Newline ) ) . )* > '"' AutoLink = AutoLinkUrl | AutoLinkEmail -AutoLinkUrl = '<' < [A-Za-z]+ "://" ( !Newline !'>' . )+ > '>' +AutoLinkUrl = ( '<' < [A-Za-z]+ "://" ( !Newline !'>' . )+ > '>' + | &{ extension(EXT_AUTOLINK) } !'[' < [A-Za-z]+ "://" ( !Newline !']' Nonspacechar )+ > !']' ) { $$ = mk_link(mk_str(yytext), yytext, ""); } AutoLinkEmail = '<' ( "mailto:" )? < [-A-Za-z0-9+_./!%~$]+ '@' ( !Newline !'>' . )+ > '>' @@ -626,7 +639,7 @@ Nonspacechar = !Spacechar !Newline . Newline = '\n' | '\r' '\n'? Sp = Spacechar* Spnl = Sp (Newline Sp)? -SpecialChar = '*' | '_' | '`' | '&' | '[' | ']' | '(' | ')' | '<' | '!' | '#' | '\\' | '\'' | '"' | ExtendedSpecialChar +SpecialChar = '~' | '*' | '_' | '`' | '&' | '[' | ']' | '(' | ')' | '<' | '!' | '#' | '\\' | '\'' | '"' | ExtendedSpecialChar NormalChar = !( SpecialChar | Spacechar | Newline ) . NonAlphanumeric = [\000-\057\072-\100\133-\140\173-\177] Alphanumeric = [0-9A-Za-z] | '\200' | '\201' | '\202' | '\203' | '\204' | '\205' | '\206' | '\207' | '\210' | '\211' | '\212' | '\213' | '\214' | '\215' | '\216' | '\217' | '\220' | '\221' | '\222' | '\223' | '\224' | '\225' | '\226' | '\227' | '\230' | '\231' | '\232' | '\233' | '\234' | '\235' | '\236' | '\237' | '\240' | '\241' | '\242' | '\243' | '\244' | '\245' | '\246' | '\247' | '\250' | '\251' | '\252' | '\253' | '\254' | '\255' | '\256' | '\257' | '\260' | '\261' | '\262' | '\263' | '\264' | '\265' | '\266' | '\267' | '\270' | '\271' | '\272' | '\273' | '\274' | '\275' | '\276' | '\277' | '\300' | '\301' | '\302' | '\303' | '\304' | '\305' | '\306' | '\307' | '\310' | '\311' | '\312' | '\313' | '\314' | '\315' | '\316' | '\317' | '\320' | '\321' | '\322' | '\323' | '\324' | '\325' | '\326' | '\327' | '\330' | '\331' | '\332' | '\333' | '\334' | '\335' | '\336' | '\337' | '\340' | '\341' | '\342' | '\343' | '\344' | '\345' | '\346' | '\347' | '\350' | '\351' | '\352' | '\353' | '\354' | '\355' | '\356' | '\357' | '\360' | '\361' | '\362' | '\363' | '\364' | '\365' | '\366' | '\367' | '\370' | '\371' | '\372' | '\373' | '\374' | '\375' | '\376' | '\377' diff --git a/markdown_peg.h b/markdown_peg.h index d70c1abd..c03d1704 100644 --- a/markdown_peg.h +++ b/markdown_peg.h @@ -37,6 +37,7 @@ enum keys { LIST, /* A generic list of values. For ordered and bullet lists, HTML, EMPH, STRONG, + STRIKE, PLAIN, PARA, LISTITEM,