From f31d151262c554a5c6e99cbd698dd40c3ca42ce6 Mon Sep 17 00:00:00 2001 From: "Fletcher T. Penney" Date: Wed, 15 Feb 2017 19:14:53 -0500 Subject: [PATCH] ADDED: Add escaped newline as linebreak; start on beamer/memoir support --- CMakeLists.txt | 6 +- src/beamer.c | 190 ++++++++++++ src/beamer.h | 67 ++++ src/latex.c | 2 + src/lexer.c | 378 ++++++++++++----------- src/lexer.re | 1 + src/libMultiMarkdown.h | 2 + src/main.c | 6 + src/memoir.c | 139 +++++++++ src/memoir.h | 67 ++++ src/writer.c | 40 ++- tests/MMD6Tests/Integrated.html | 1 + tests/MMD6Tests/Metadata.htmlc | 8 +- tests/MMD6Tests/Metadata.tex | 6 +- tests/MMD6Tests/Metadata.text | 6 +- tests/MMD6Tests/Special Characters.html | 17 + tests/MMD6Tests/Special Characters.htmlc | 17 + tests/MMD6Tests/Special Characters.tex | 17 + tests/MMD6Tests/Special Characters.text | 17 + tests/MMD6Tests/What Is MMD.text | 227 ++++++++++++++ 20 files changed, 1018 insertions(+), 196 deletions(-) create mode 100644 src/beamer.c create mode 100644 src/beamer.h create mode 100644 src/memoir.c create mode 100644 src/memoir.h create mode 100644 tests/MMD6Tests/Special Characters.html create mode 100644 tests/MMD6Tests/Special Characters.htmlc create mode 100644 tests/MMD6Tests/Special Characters.tex create mode 100644 tests/MMD6Tests/Special Characters.text create mode 100644 tests/MMD6Tests/What Is MMD.text diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e30982..c835efb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -168,11 +168,13 @@ configure_file ( # src_files are the primary files, and will be included in doxygen documentation set(src_files src/argtable3.c + src/beamer.c src/char.c src/d_string.c src/html.c src/latex.c src/lexer.c + src/memoir.c src/mmd.c src/object_pool.c src/parser.c @@ -188,12 +190,14 @@ set(src_files # Primary header files, also for doxygen documentation set(header_files src/argtable3.h - src/d_string.h + src/beamer.h src/char.h + src/d_string.h src/html.h src/latex.h src/lexer.h src/libMultiMarkdown.h + src/memoir.h src/mmd.h src/object_pool.h src/scanners.h diff --git a/src/beamer.c b/src/beamer.c new file mode 100644 index 0000000..9e2855a --- /dev/null +++ b/src/beamer.c @@ -0,0 +1,190 @@ +/** + + MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more. + + @file beamer.c + + @brief + + + @author Fletcher T. Penney + @bug + +**/ + +/* + + Copyright © 2016 - 2017 Fletcher T. Penney. + + + The `MultiMarkdown 6` project is released under the MIT License.. + + GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project: + + https://github.com/fletcher/MultiMarkdown-4/ + + MMD 4 is released under both the MIT License and GPL. + + + CuTest is released under the zlib/libpng license. See CuTest.c for the text + of the license. + + + ## The MIT License ## + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + + +#include "latex.h" +#include "beamer.h" + +#define print(x) d_string_append(out, x) +#define print_char(x) d_string_append_c(out, x) +#define printf(...) d_string_append_printf(out, __VA_ARGS__) +#define print_token(t) d_string_append_c_array(out, &(source[t->start]), t->len) +#define print_localized(x) mmd_print_localized_char_latex(out, x, scratch) + + +void mmd_export_token_beamer(DString * out, const char * source, token * t, scratch_pad * scratch) { + if (t == NULL) + return; + + short temp_short; + short temp_short2; + link * temp_link = NULL; + char * temp_char = NULL; + char * temp_char2 = NULL; + char * temp_char3 = NULL; + bool temp_bool = 0; + token * temp_token = NULL; + footnote * temp_note = NULL; + + switch (t->type) { + case DOC_START_TOKEN: + mmd_export_token_tree_beamer(out, source, t->child, scratch); + break; + case BLOCK_CODE_FENCED: + pad(out, 2, scratch); + + temp_char = get_fence_language_specifier(t->child->child, source); + if (temp_char) { + printf("\\begin{lstlisting}[language=%s]\n", temp_char); + } else { + print("\\begin{verbatim}\n"); + } + + mmd_export_token_tree_latex_raw(out, source, t->child->next, scratch); + + if (temp_char) { + print("\\end{lstlisting}"); + free(temp_char); + } else { + print("\\end{verbatim}"); + } + scratch->padded = 0; + break; + case BLOCK_CODE_INDENTED: + pad(out, 2, scratch); + print("\\begin{verbatim}\n"); + mmd_export_token_tree_latex_raw(out, source, t->child, scratch); + print("\\end{verbatim}"); + scratch->padded = 0; + break; + case BLOCK_H1: + case BLOCK_H2: + case BLOCK_H3: + case BLOCK_H4: + case BLOCK_H5: + case BLOCK_H6: + case BLOCK_SETEXT_1: + case BLOCK_SETEXT_2: + pad(out, 2, scratch); + switch (t->type) { + case BLOCK_SETEXT_1: + temp_short = 1; + break; + case BLOCK_SETEXT_2: + temp_short = 2; + break; + default: + temp_short = t->type - BLOCK_H1 + 1; + } + + switch (temp_short + scratch->base_header_level - 1) { + case 1: + print("\\part{"); + break; + case 2: + print("\\section{"); + break; + case 3: + print("\\begin{frame}\n\\frametitle{"); + break; + default: + print("\\emph{"); + break; + } + + mmd_export_token_tree_beamer(out, source, t->child, scratch); + + if (scratch->extensions & EXT_NO_LABELS) { + print("}"); + } else { + temp_token = manual_label_from_header(t, source); + if (temp_token) { + temp_char = label_from_token(source, temp_token); + } else { + temp_char = label_from_token(source, t); + } + printf("}\n\\label{%s}", temp_char); + free(temp_char); + } + scratch->padded = 0; + break; + default: + // Default to LaTeX behavior + mmd_export_token_latex(out, source, t, scratch); + } +} + + +void mmd_export_token_tree_beamer(DString * out, const char * source, token * t, scratch_pad * scratch) { + + // Prevent stack overflow with "dangerous" input causing extreme recursion + if (scratch->recurse_depth == kMaxExportRecursiveDepth) { + return; + } + + scratch->recurse_depth++; + + while (t != NULL) { + if (scratch->skip_token) { + scratch->skip_token--; + } else { + mmd_export_token_beamer(out, source, t, scratch); + } + + t = t->next; + } + + scratch->recurse_depth--; +} + diff --git a/src/beamer.h b/src/beamer.h new file mode 100644 index 0000000..f23f089 --- /dev/null +++ b/src/beamer.h @@ -0,0 +1,67 @@ +/** + + MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more. + + @file beamer.h + + @brief + + + @author Fletcher T. Penney + @bug + +**/ + +/* + + Copyright © 2016 - 2017 Fletcher T. Penney. + + + The `MultiMarkdown 6` project is released under the MIT License.. + + GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project: + + https://github.com/fletcher/MultiMarkdown-4/ + + MMD 4 is released under both the MIT License and GPL. + + + CuTest is released under the zlib/libpng license. See CuTest.c for the text + of the license. + + + ## The MIT License ## + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + + +#ifndef BEAMER_MULTIMARKDOWN_6_H +#define BEAMER_MULTIMARKDOWN_6_H + +#include "d_string.h" +#include "token.h" +#include "writer.h" + +void mmd_export_token_beamer(DString * out, const char * source, token * t, scratch_pad * scratch); +void mmd_export_token_tree_beamer(DString * out, const char * source, token * t, scratch_pad * scratch); + + +#endif diff --git a/src/latex.c b/src/latex.c index 2a0070b..ed627d6 100644 --- a/src/latex.c +++ b/src/latex.c @@ -1582,6 +1582,8 @@ void mmd_start_complete_latex(DString * out, const char * source, scratch_pad * } else if (strcmp(m->key, "lang") == 0) { } else if (strcmp(m->key, "latexbegin") == 0) { } else if (strcmp(m->key, "latexheader") == 0) { + print(m->value); + print_char('\n'); } else if (strcmp(m->key, "latexfooter") == 0) { } else if (strcmp(m->key, "latexheaderlevel") == 0) { } else if (strcmp(m->key, "latexinput") == 0) { diff --git a/src/lexer.c b/src/lexer.c index 28227fd..f4ea5df 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -1,4 +1,4 @@ -/* Generated by re2c 0.14.3 on Mon Feb 13 10:36:45 2017 */ +/* Generated by re2c 0.14.3 on Wed Feb 15 19:09:41 2017 */ /** MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more. @@ -132,12 +132,12 @@ yy2: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); switch (yych) { - case '+': goto yy262; - case '-': goto yy261; - case '=': goto yy258; - case '>': goto yy260; - case '{': goto yy256; - case '~': goto yy259; + case '+': goto yy265; + case '-': goto yy264; + case '=': goto yy261; + case '>': goto yy263; + case '{': goto yy259; + case '~': goto yy262; default: goto yy3; } yy3: @@ -146,7 +146,7 @@ yy4: yyaccept = 1; yych = *(YYMARKER = ++YYCURSOR); switch (yych) { - case '+': goto yy253; + case '+': goto yy256; default: goto yy5; } yy5: @@ -154,7 +154,7 @@ yy5: yy6: ++YYCURSOR; switch ((yych = *YYCURSOR)) { - case '-': goto yy247; + case '-': goto yy250; default: goto yy7; } yy7: @@ -163,7 +163,7 @@ yy8: yyaccept = 2; yych = *(YYMARKER = ++YYCURSOR); switch (yych) { - case '<': goto yy244; + case '<': goto yy247; default: goto yy9; } yy9: @@ -172,8 +172,8 @@ yy10: yyaccept = 3; yych = *(YYMARKER = ++YYCURSOR); switch (yych) { - case '>': goto yy240; - case '~': goto yy239; + case '>': goto yy243; + case '~': goto yy242; default: goto yy11; } yy11: @@ -182,7 +182,7 @@ yy12: yyaccept = 4; yych = *(YYMARKER = ++YYCURSOR); switch (yych) { - case '=': goto yy236; + case '=': goto yy239; default: goto yy13; } yy13: @@ -190,9 +190,9 @@ yy13: yy14: ++YYCURSOR; switch ((yych = *YYCURSOR)) { - case '#': goto yy232; - case '%': goto yy230; - case '^': goto yy234; + case '#': goto yy235; + case '%': goto yy233; + case '^': goto yy237; default: goto yy15; } yy15: @@ -203,7 +203,7 @@ yy16: yy18: ++YYCURSOR; switch ((yych = *YYCURSOR)) { - case '[': goto yy228; + case '[': goto yy231; default: goto yy19; } yy19: @@ -220,7 +220,7 @@ yy24: yy26: ++YYCURSOR; switch ((yych = *YYCURSOR)) { - case '}': goto yy226; + case '}': goto yy229; default: goto yy27; } yy27: @@ -231,7 +231,7 @@ yy28: yy30: ++YYCURSOR; switch ((yych = *YYCURSOR)) { - case '\'': goto yy224; + case '\'': goto yy227; default: goto yy31; } yy31: @@ -241,11 +241,11 @@ yy32: yyaccept = 5; yych = *(YYMARKER = ++YYCURSOR); switch (yych) { - case '\t': goto yy214; - case '\n': goto yy211; - case '\r': goto yy213; - case ' ': goto yy216; - case '.': goto yy217; + case '\t': goto yy217; + case '\n': goto yy214; + case '\r': goto yy216; + case ' ': goto yy219; + case '.': goto yy220; default: goto yy19; } yy33: @@ -256,7 +256,7 @@ yy35: yych = *(YYMARKER = ++YYCURSOR); switch (yych) { case 'A': - case 'a': goto yy206; + case 'a': goto yy209; default: goto yy36; } yy36: @@ -267,39 +267,41 @@ yy37: yy39: ++YYCURSOR; switch ((yych = *YYCURSOR)) { - case ' ': goto yy134; - case '!': goto yy194; - case '"': goto yy184; - case '#': goto yy164; - case '$': goto yy162; - case '%': goto yy160; - case '&': goto yy148; - case '\'': goto yy182; - case '(': goto yy176; - case ')': goto yy174; - case '*': goto yy140; - case '+': goto yy158; - case ',': goto yy190; - case '-': goto yy156; - case '.': goto yy196; - case '/': goto yy144; - case ':': goto yy186; - case ';': goto yy188; - case '<': goto yy152; - case '=': goto yy154; - case '>': goto yy150; - case '?': goto yy192; - case '@': goto yy146; - case '[': goto yy168; - case '\\': goto yy132; - case ']': goto yy166; - case '^': goto yy142; - case '_': goto yy138; - case '`': goto yy180; - case '{': goto yy172; - case '|': goto yy136; - case '}': goto yy170; - case '~': goto yy178; + case '\n': goto yy132; + case '\r': goto yy134; + case ' ': goto yy137; + case '!': goto yy197; + case '"': goto yy187; + case '#': goto yy167; + case '$': goto yy165; + case '%': goto yy163; + case '&': goto yy151; + case '\'': goto yy185; + case '(': goto yy179; + case ')': goto yy177; + case '*': goto yy143; + case '+': goto yy161; + case ',': goto yy193; + case '-': goto yy159; + case '.': goto yy199; + case '/': goto yy147; + case ':': goto yy189; + case ';': goto yy191; + case '<': goto yy155; + case '=': goto yy157; + case '>': goto yy153; + case '?': goto yy195; + case '@': goto yy149; + case '[': goto yy171; + case '\\': goto yy135; + case ']': goto yy169; + case '^': goto yy145; + case '_': goto yy141; + case '`': goto yy183; + case '{': goto yy175; + case '|': goto yy139; + case '}': goto yy173; + case '~': goto yy181; default: goto yy40; } yy40: @@ -429,8 +431,8 @@ yy70: case 6: goto yy36; case 7: goto yy49; case 8: goto yy127; - case 9: goto yy212; - default: goto yy257; + case 9: goto yy215; + default: goto yy260; } yy71: YYCTXMARKER = YYCURSOR + 1; @@ -726,348 +728,358 @@ yy130: { return MATH_DOLLAR_DOUBLE; } yy132: ++YYCURSOR; - switch ((yych = *YYCURSOR)) { - case '(': goto yy198; - case ')': goto yy200; - case '[': goto yy202; - case ']': goto yy204; +yy133: + { return TEXT_LINEBREAK; } +yy134: + yych = *++YYCURSOR; + switch (yych) { + case '\n': goto yy132; default: goto yy133; } -yy133: +yy135: + ++YYCURSOR; + switch ((yych = *YYCURSOR)) { + case '(': goto yy201; + case ')': goto yy203; + case '[': goto yy205; + case ']': goto yy207; + default: goto yy136; + } +yy136: { return ESCAPED_CHARACTER; } -yy134: +yy137: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy136: +yy139: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy138: +yy141: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy140: +yy143: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy142: +yy145: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy144: +yy147: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy146: +yy149: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy148: +yy151: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy150: +yy153: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy152: +yy155: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy154: +yy157: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy156: +yy159: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy158: +yy161: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy160: +yy163: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy162: +yy165: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy164: +yy167: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy166: +yy169: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy168: +yy171: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy170: +yy173: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy172: +yy175: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy174: +yy177: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy176: +yy179: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy178: +yy181: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy180: +yy183: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy182: +yy185: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy184: +yy187: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy186: +yy189: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy188: +yy191: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy190: +yy193: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy192: +yy195: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy194: +yy197: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy196: +yy199: ++YYCURSOR; { return ESCAPED_CHARACTER; } -yy198: +yy201: ++YYCURSOR; { return MATH_PAREN_OPEN; } -yy200: +yy203: ++YYCURSOR; { return MATH_PAREN_CLOSE; } -yy202: +yy205: ++YYCURSOR; { return MATH_BRACKET_OPEN; } -yy204: +yy207: ++YYCURSOR; { return MATH_BRACKET_CLOSE; } -yy206: +yy209: yych = *++YYCURSOR; switch (yych) { case 'M': - case 'm': goto yy207; + case 'm': goto yy210; default: goto yy70; } -yy207: +yy210: yych = *++YYCURSOR; switch (yych) { case 'P': - case 'p': goto yy208; + case 'p': goto yy211; default: goto yy70; } -yy208: +yy211: yych = *++YYCURSOR; switch (yych) { - case ';': goto yy209; + case ';': goto yy212; default: goto yy70; } -yy209: +yy212: ++YYCURSOR; { return AMPERSAND_LONG; } -yy211: +yy214: ++YYCURSOR; -yy212: +yy215: YYCURSOR = YYCTXMARKER; { return TEXT_PERIOD; } -yy213: +yy216: yych = *++YYCURSOR; switch (yych) { - case '\n': goto yy211; - default: goto yy212; + case '\n': goto yy214; + default: goto yy215; } -yy214: +yy217: ++YYCURSOR; yych = *YYCURSOR; -yy215: +yy218: switch (yych) { case '\t': - case ' ': goto yy214; - default: goto yy212; + case ' ': goto yy217; + default: goto yy215; } -yy216: +yy219: yyaccept = 9; yych = *(YYMARKER = ++YYCURSOR); switch (yych) { - case '.': goto yy220; - default: goto yy215; + case '.': goto yy223; + default: goto yy218; } -yy217: +yy220: yych = *++YYCURSOR; switch (yych) { - case '.': goto yy218; + case '.': goto yy221; default: goto yy70; } -yy218: +yy221: ++YYCURSOR; { return ELLIPSIS; } -yy220: +yy223: yych = *++YYCURSOR; switch (yych) { - case ' ': goto yy221; + case ' ': goto yy224; default: goto yy70; } -yy221: +yy224: yych = *++YYCURSOR; switch (yych) { - case '.': goto yy222; + case '.': goto yy225; default: goto yy70; } -yy222: +yy225: ++YYCURSOR; { return ELLIPSIS; } -yy224: +yy227: ++YYCURSOR; { return QUOTE_RIGHT_ALT; } -yy226: +yy229: ++YYCURSOR; { return BRACE_DOUBLE_RIGHT; } -yy228: +yy231: ++YYCURSOR; { return BRACKET_IMAGE_LEFT; } -yy230: +yy233: ++YYCURSOR; { return BRACKET_VARIABLE_LEFT; } -yy232: +yy235: ++YYCURSOR; { return BRACKET_CITATION_LEFT; } -yy234: +yy237: ++YYCURSOR; { return BRACKET_FOOTNOTE_LEFT; } -yy236: +yy239: yych = *++YYCURSOR; switch (yych) { - case '}': goto yy237; + case '}': goto yy240; default: goto yy70; } -yy237: +yy240: ++YYCURSOR; { return CRITIC_HI_CLOSE; } -yy239: +yy242: yych = *++YYCURSOR; switch (yych) { - case '}': goto yy242; + case '}': goto yy245; default: goto yy70; } -yy240: +yy243: ++YYCURSOR; { return CRITIC_SUB_DIV; } -yy242: +yy245: ++YYCURSOR; { return CRITIC_SUB_CLOSE; } -yy244: +yy247: yych = *++YYCURSOR; switch (yych) { - case '}': goto yy245; + case '}': goto yy248; default: goto yy70; } -yy245: +yy248: ++YYCURSOR; { return CRITIC_COM_CLOSE; } -yy247: +yy250: ++YYCURSOR; switch ((yych = *YYCURSOR)) { - case '-': goto yy251; - case '}': goto yy249; - default: goto yy248; + case '-': goto yy254; + case '}': goto yy252; + default: goto yy251; } -yy248: +yy251: { return DASH_N; } -yy249: +yy252: ++YYCURSOR; { return CRITIC_DEL_CLOSE; } -yy251: +yy254: ++YYCURSOR; { return DASH_M; } -yy253: +yy256: yych = *++YYCURSOR; switch (yych) { - case '}': goto yy254; + case '}': goto yy257; default: goto yy70; } -yy254: +yy257: ++YYCURSOR; { return CRITIC_ADD_CLOSE; } -yy256: +yy259: yyaccept = 10; yych = *(YYMARKER = ++YYCURSOR); switch (yych) { - case 'T': goto yy273; - default: goto yy257; + case 'T': goto yy276; + default: goto yy260; } -yy257: +yy260: { return BRACE_DOUBLE_LEFT; } -yy258: +yy261: yych = *++YYCURSOR; switch (yych) { - case '=': goto yy271; + case '=': goto yy274; default: goto yy70; } -yy259: +yy262: yych = *++YYCURSOR; switch (yych) { - case '~': goto yy269; + case '~': goto yy272; default: goto yy70; } -yy260: +yy263: yych = *++YYCURSOR; switch (yych) { - case '>': goto yy267; + case '>': goto yy270; default: goto yy70; } -yy261: +yy264: yych = *++YYCURSOR; switch (yych) { - case '-': goto yy265; + case '-': goto yy268; default: goto yy70; } -yy262: +yy265: yych = *++YYCURSOR; switch (yych) { - case '+': goto yy263; + case '+': goto yy266; default: goto yy70; } -yy263: +yy266: ++YYCURSOR; { return CRITIC_ADD_OPEN; } -yy265: +yy268: ++YYCURSOR; { return CRITIC_DEL_OPEN; } -yy267: +yy270: ++YYCURSOR; { return CRITIC_COM_OPEN; } -yy269: +yy272: ++YYCURSOR; { return CRITIC_SUB_OPEN; } -yy271: +yy274: ++YYCURSOR; { return CRITIC_HI_OPEN; } -yy273: +yy276: yych = *++YYCURSOR; switch (yych) { - case 'O': goto yy274; + case 'O': goto yy277; default: goto yy70; } -yy274: +yy277: yych = *++YYCURSOR; switch (yych) { - case 'C': goto yy275; + case 'C': goto yy278; default: goto yy70; } -yy275: +yy278: yych = *++YYCURSOR; switch (yych) { - case '}': goto yy276; + case '}': goto yy279; default: goto yy70; } -yy276: +yy279: yych = *++YYCURSOR; switch (yych) { - case '}': goto yy277; + case '}': goto yy280; default: goto yy70; } -yy277: +yy280: ++YYCURSOR; { return TOC; } } diff --git a/src/lexer.re b/src/lexer.re index 4d4f8d8..36684dc 100644 --- a/src/lexer.re +++ b/src/lexer.re @@ -220,6 +220,7 @@ int scan(Scanner * s, const char * stop) { '.' / (SP|NL) { return TEXT_PERIOD; } TEXT_LINEBREAK { return TEXT_LINEBREAK; } + '\\' NL { return TEXT_LINEBREAK; } ' '? NL { return TEXT_NL; } NON_INDENT_SPACE { return NON_INDENT_SPACE; } diff --git a/src/libMultiMarkdown.h b/src/libMultiMarkdown.h index b4ceffb..7768577 100644 --- a/src/libMultiMarkdown.h +++ b/src/libMultiMarkdown.h @@ -302,8 +302,10 @@ enum smart_quotes_language { enum output_format { FORMAT_MMD, + FORMAT_BEAMER, FORMAT_HTML, FORMAT_LATEX, + FORMAT_MEMOIR, FORMAT_ODF, }; diff --git a/src/main.c b/src/main.c index 8a1fdfd..2e4da5a 100644 --- a/src/main.c +++ b/src/main.c @@ -292,6 +292,10 @@ int main(int argc, char** argv) { format = FORMAT_HTML; else if (strcmp(a_format->sval[0], "latex") == 0) format = FORMAT_LATEX; + else if (strcmp(a_format->sval[0], "beamer") == 0) + format = FORMAT_BEAMER; + else if (strcmp(a_format->sval[0], "memoir") == 0) + format = FORMAT_MEMOIR; else { // No valid format found fprintf(stderr, "%s: Unknown output format '%s'\n", binname, a_format->sval[0]); @@ -341,6 +345,8 @@ int main(int argc, char** argv) { output_filename = filename_with_extension(a_file->filename[i], ".html"); break; case FORMAT_LATEX: + case FORMAT_BEAMER: + case FORMAT_MEMOIR: output_filename = filename_with_extension(a_file->filename[i], ".tex"); break; } diff --git a/src/memoir.c b/src/memoir.c new file mode 100644 index 0000000..841cee1 --- /dev/null +++ b/src/memoir.c @@ -0,0 +1,139 @@ +/** + + MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more. + + @file memoir.c + + @brief + + + @author Fletcher T. Penney + @bug + +**/ + +/* + + Copyright © 2016 - 2017 Fletcher T. Penney. + + + The `MultiMarkdown 6` project is released under the MIT License.. + + GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project: + + https://github.com/fletcher/MultiMarkdown-4/ + + MMD 4 is released under both the MIT License and GPL. + + + CuTest is released under the zlib/libpng license. See CuTest.c for the text + of the license. + + + ## The MIT License ## + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + + +#include "latex.h" +#include "memoir.h" + +#define print(x) d_string_append(out, x) +#define print_char(x) d_string_append_c(out, x) +#define printf(...) d_string_append_printf(out, __VA_ARGS__) +#define print_token(t) d_string_append_c_array(out, &(source[t->start]), t->len) +#define print_localized(x) mmd_print_localized_char_latex(out, x, scratch) + + +void mmd_export_token_memoir(DString * out, const char * source, token * t, scratch_pad * scratch) { + if (t == NULL) + return; + + short temp_short; + short temp_short2; + link * temp_link = NULL; + char * temp_char = NULL; + char * temp_char2 = NULL; + char * temp_char3 = NULL; + bool temp_bool = 0; + token * temp_token = NULL; + footnote * temp_note = NULL; + + switch (t->type) { + case DOC_START_TOKEN: + mmd_export_token_tree_memoir(out, source, t->child, scratch); + break; + case BLOCK_CODE_FENCED: + pad(out, 2, scratch); + + temp_char = get_fence_language_specifier(t->child->child, source); + if (temp_char) { + printf("\\begin{adjustwidth}{2.5em}{2.5em}\n\\begin{lstlisting}[language=%s]\n", temp_char); + } else { + print("\\begin{adjustwidth}{2.5em}{2.5em}\n\\begin{verbatim}\n"); + } + + mmd_export_token_tree_latex_raw(out, source, t->child->next, scratch); + + if (temp_char) { + print("\\end{lstlisting}\n\\end{adjustwidth}"); + free(temp_char); + } else { + print("\\end{verbatim}\n\\end{adjustwidth}"); + } + scratch->padded = 0; + break; + case BLOCK_CODE_INDENTED: + pad(out, 2, scratch); + print("\\begin{adjustwidth}{2.5em}{2.5em}\\begin{verbatim}\n"); + mmd_export_token_tree_latex_raw(out, source, t->child, scratch); + print("\\end{verbatim}\n\\end{adjustwidth}"); + scratch->padded = 0; + break; + default: + // Default to LaTeX behavior + mmd_export_token_latex(out, source, t, scratch); + } +} + + +void mmd_export_token_tree_memoir(DString * out, const char * source, token * t, scratch_pad * scratch) { + + // Prevent stack overflow with "dangerous" input causing extreme recursion + if (scratch->recurse_depth == kMaxExportRecursiveDepth) { + return; + } + + scratch->recurse_depth++; + + while (t != NULL) { + if (scratch->skip_token) { + scratch->skip_token--; + } else { + mmd_export_token_memoir(out, source, t, scratch); + } + + t = t->next; + } + + scratch->recurse_depth--; +} + diff --git a/src/memoir.h b/src/memoir.h new file mode 100644 index 0000000..6d6aa2d --- /dev/null +++ b/src/memoir.h @@ -0,0 +1,67 @@ +/** + + MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more. + + @file memoir.h + + @brief + + + @author Fletcher T. Penney + @bug + +**/ + +/* + + Copyright © 2016 - 2017 Fletcher T. Penney. + + + The `MultiMarkdown 6` project is released under the MIT License.. + + GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project: + + https://github.com/fletcher/MultiMarkdown-4/ + + MMD 4 is released under both the MIT License and GPL. + + + CuTest is released under the zlib/libpng license. See CuTest.c for the text + of the license. + + + ## The MIT License ## + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + + +#ifndef MEMOIR_MULTIMARKDOWN_6_H +#define MEMOIR_MULTIMARKDOWN_6_H + +#include "d_string.h" +#include "token.h" +#include "writer.h" + +void mmd_export_token_memoir(DString * out, const char * source, token * t, scratch_pad * scratch); +void mmd_export_token_tree_memoir(DString * out, const char * source, token * t, scratch_pad * scratch); + + +#endif diff --git a/src/writer.c b/src/writer.c index 218c576..bf02130 100644 --- a/src/writer.c +++ b/src/writer.c @@ -59,11 +59,13 @@ #include "libMultiMarkdown.h" +#include "beamer.h" #include "char.h" #include "d_string.h" #include "html.h" #include "i18n.h" #include "latex.h" +#include "memoir.h" #include "mmd.h" #include "scanners.h" #include "token.h" @@ -1229,7 +1231,9 @@ void process_metadata_stack(mmd_engine * e, scratch_pad * scratch) { if (scratch->output_format == FORMAT_HTML) header_level = atoi(m->value); } else if (strcmp(m->key, "latexheaderlevel") == 0) { - if (scratch->output_format == FORMAT_LATEX) + if ((scratch->output_format == FORMAT_LATEX) || + (scratch->output_format == FORMAT_BEAMER) || + (scratch->output_format == FORMAT_MEMOIR)) header_level = atoi(m->value); } else if (strcmp(m->key, "odfheaderlevel") == 0) { if (scratch->output_format == FORMAT_ODF) @@ -1254,6 +1258,16 @@ void process_metadata_stack(mmd_engine * e, scratch_pad * scratch) { scratch->quotes_lang = ENGLISH; } + free(temp_char); + } else if (strcmp(m->key, "latexmode") == 0) { + temp_char = label_from_string(m->value); + + if (strcmp(temp_char, "beamer") == 0) { + scratch->output_format = FORMAT_BEAMER; + } else if (strcmp(temp_char, "memoir") == 0) { + scratch->output_format = FORMAT_MEMOIR; + } + free(temp_char); } else if (strcmp(m->key, "quoteslanguage") == 0) { temp_char = label_from_string(m->value); @@ -1305,7 +1319,18 @@ void mmd_export_token_tree(DString * out, mmd_engine * e, short format) { process_metadata_stack(e, scratch); - switch (format) { + switch (scratch->output_format) { + case FORMAT_BEAMER: + if (scratch->extensions & EXT_COMPLETE) + mmd_start_complete_latex(out, e->dstr->str, scratch); + + mmd_export_token_tree_beamer(out, e->dstr->str, e->root, scratch); + mmd_export_citation_list_latex(out, e->dstr->str, scratch); + + if (scratch->extensions & EXT_COMPLETE) + mmd_end_complete_latex(out, e->dstr->str, scratch); + + break; case FORMAT_HTML: if (scratch->extensions & EXT_COMPLETE) mmd_start_complete_html(out, e->dstr->str, scratch); @@ -1325,6 +1350,17 @@ void mmd_export_token_tree(DString * out, mmd_engine * e, short format) { mmd_export_token_tree_latex(out, e->dstr->str, e->root, scratch); mmd_export_citation_list_latex(out, e->dstr->str, scratch); + if (scratch->extensions & EXT_COMPLETE) + mmd_end_complete_latex(out, e->dstr->str, scratch); + + break; + case FORMAT_MEMOIR: + if (scratch->extensions & EXT_COMPLETE) + mmd_start_complete_latex(out, e->dstr->str, scratch); + + mmd_export_token_tree_memoir(out, e->dstr->str, e->root, scratch); + mmd_export_citation_list_latex(out, e->dstr->str, scratch); + if (scratch->extensions & EXT_COMPLETE) mmd_end_complete_latex(out, e->dstr->str, scratch); diff --git a/tests/MMD6Tests/Integrated.html b/tests/MMD6Tests/Integrated.html index 00387d0..0b3798b 100644 --- a/tests/MMD6Tests/Integrated.html +++ b/tests/MMD6Tests/Integrated.html @@ -132,6 +132,7 @@ code
  • bar +  ↩

  • diff --git a/tests/MMD6Tests/Metadata.htmlc b/tests/MMD6Tests/Metadata.htmlc index 4bb8014..b1d5708 100644 --- a/tests/MMD6Tests/Metadata.htmlc +++ b/tests/MMD6Tests/Metadata.htmlc @@ -1,11 +1,11 @@ -

    latex leader: mmd-article-header -title: foo "bar" +

    title: foo "bar" css: http://foo.com/bar.css HTML header: -latex begin: mmd-article-begin-doc -latex footer: mmd-memoir-footer +latex leader: mmd6-article-leader +latex begin: mmd6-article-begin +latex footer: mmd6-article-footer foo: bar foo bar foo bar diff --git a/tests/MMD6Tests/Metadata.tex b/tests/MMD6Tests/Metadata.tex index fdedcb3..c89ae48 100644 --- a/tests/MMD6Tests/Metadata.tex +++ b/tests/MMD6Tests/Metadata.tex @@ -1,13 +1,13 @@ -\input{mmd-article-header} +\input{mmd6-article-leader} \def\mytitle{*foo* "bar"} \def\foo{bar foo bar foo bar} -\input{mmd-article-begin-doc} +\input{mmd6-article-begin} foo: bar \chapter{foo } \label{foo} -\input{mmd-memoir-footer} +\input{mmd6-article-footer} \end{document} diff --git a/tests/MMD6Tests/Metadata.text b/tests/MMD6Tests/Metadata.text index b1e8e1f..0a6a82b 100644 --- a/tests/MMD6Tests/Metadata.text +++ b/tests/MMD6Tests/Metadata.text @@ -1,11 +1,11 @@ -latex leader: mmd-article-header title: *foo* "bar" css: http://foo.com/bar.css HTML header: -latex begin: mmd-article-begin-doc -latex footer: mmd-memoir-footer +latex leader: mmd6-article-leader +latex begin: mmd6-article-begin +latex footer: mmd6-article-footer foo: bar foo bar foo bar diff --git a/tests/MMD6Tests/Special Characters.html b/tests/MMD6Tests/Special Characters.html new file mode 100644 index 0000000..ca310e3 --- /dev/null +++ b/tests/MMD6Tests/Special Characters.html @@ -0,0 +1,17 @@ +

    {foo}

    + +

    [foo]

    + +

    {{foo}}

    + +

    [[foo]]

    + +

    (foo)

    + +

    5

    + +

    |foo|

    + +

    \foo

    + + diff --git a/tests/MMD6Tests/Special Characters.htmlc b/tests/MMD6Tests/Special Characters.htmlc new file mode 100644 index 0000000..ca310e3 --- /dev/null +++ b/tests/MMD6Tests/Special Characters.htmlc @@ -0,0 +1,17 @@ +

    {foo}

    + +

    [foo]

    + +

    {{foo}}

    + +

    [[foo]]

    + +

    (foo)

    + +

    5

    + +

    |foo|

    + +

    \foo

    + + diff --git a/tests/MMD6Tests/Special Characters.tex b/tests/MMD6Tests/Special Characters.tex new file mode 100644 index 0000000..49a7b5b --- /dev/null +++ b/tests/MMD6Tests/Special Characters.tex @@ -0,0 +1,17 @@ +\{foo\} + +[foo] + +\{\{foo\}\} + +[[foo]] + +(foo) + +5 + +\textbar{}foo\textbar{} + +\textbackslash{}foo + + diff --git a/tests/MMD6Tests/Special Characters.text b/tests/MMD6Tests/Special Characters.text new file mode 100644 index 0000000..edcc04e --- /dev/null +++ b/tests/MMD6Tests/Special Characters.text @@ -0,0 +1,17 @@ +{foo} + +[foo] + +{{foo}} + +[[foo]] + +(foo) + +5 + +|foo| + +\foo\ + + diff --git a/tests/MMD6Tests/What Is MMD.text b/tests/MMD6Tests/What Is MMD.text new file mode 100644 index 0000000..a29c0c8 --- /dev/null +++ b/tests/MMD6Tests/What Is MMD.text @@ -0,0 +1,227 @@ +latex leader: mmd-beamer-header +Title: What is MultiMarkdown? +Subtitle: And why should you care? +Author: Fletcher T. Penney +Affiliation: http://fletcherpenney.net/multimarkdown/ +Copyright: 2009-2011 Fletcher T. Penney. + This work is licensed under a Creative Commons License. + http://creativecommons.org/licenses/by-sa/2.5/ +base header level: 3 +latex mode: beamer +latex header: \input{mmd-natbib-plain} +Theme: keynote-gradient +latex begin: mmd-beamer-begin-doc +latex footer: mmd-beamer-footer + + +# MultiMarkdown is a derivative of Markdown # + +[Markdown](http://daringfireball.net/projects/markdown/) is a program and a +syntax by John Gruber that allows you to easily convert plain text into HTML +suitable for using on a web page. + + +# The old way was complicated # + +

    In order to create valid + HTML, you + need properly coded syntax that can be cumbersome for + “non-programmers” to write. Sometimes, you + just want to easily make certain words bold + , and certain words italicized without + having to remember the syntax. Additionally, for example, + creating lists:

    + +
      +
    • should be easy
    • +
    • should not involve programming
    • +
    + + +# The new way is easier # + + In order to create valid [HTML], you need properly + coded syntax that can be cumbersome for + "non-programmers" to write. Sometimes, you just want + to easily make certain words **bold**, and certain + words *italicized* without having to remember the + syntax. Additionally, for example, creating lists: + + * should be easy + * should not involve programming + + [HTML]: http://en.wikipedia.org/wiki/HTML + + +# Markdown is designed for people # + +The overriding design goal for Markdown's formatting syntax is to make it as +readable as possible. The idea is that a Markdown-formatted document should be +publishable as-is, as plain text, without looking like it's been marked up +with tags or formatting instructions. While Markdown's syntax has been +influenced by several existing text-to-HTML filters, the single biggest source +of inspiration for Markdown's syntax is the format of plain text email. +[][#Gruber] + + +[#Gruber]: John Gruber. Daring Fireball: Markdown. [Cited January 2006]. Available from . + + +# But Markdown wasn't complete # + +I, and others, loved the spirit and elegance of Markdown, but felt it was +still missing a few features that each of us considered were essential. +Several variations on Markdown arose to meet the needs of these other +programmers. + + +# MultiMarkdown adds several new features # + +* footnotes +* tables +* citations and bibliography +* image attributes +* metadata +* internal cross-references +* math support +* glossary entries +* definition lists +* and more... + + +# MMD also adds something else... # + +* Outside of the actual syntax, MMD supports multiple output formats, + including HTML, [LaTeX](http://en.wikipedia.org/wiki/LaTeX), + [OpenDocument](http://en.wikipedia.org/wiki/OpenDocument), and + [OPML](http://en.wikipedia.org/wiki/OPML) + +* This allows you to use the same markup language (MultiMarkdown) to create a + high quality pdf (article, book, or presentation like this one) without any + additional programming. + +* Most importantly, you don't have to know how this works, or even what + the LaTeX commands mean --- just have the software installed. + + +# So, one text file becomes multiple final documents # + + +![Example MultiMarkdown output formats](OPML-MMD-Map.pdf) + + +# The goal is to separate content from formatting # + +By focusing on the text content of your document, you can focus on the +creative, the scientific, the *human*. Let your computer do what it is good at +--- the fairly boring job of making sure that margins are correct, that +paragraphs are properly separated, your footnotes are in order, and that your +tables line up --- regardless of the final format you want your document to +take. + + +# MultiMarkdown and Mathematics # + +Built into MultiMarkdown is support for mathematical equations. You write +using LaTeX syntax. When you output to HTML, you can use +[MathJax](http://www.mathjax.org/) to properly display the math. If you output +to LaTeX, it is display automatically. There is not currently an approach to +display math using OpenDocument + + \\[ {e}^{i\pi }+1=0 \\] + +becomes + +\\[ {e}^{i\pi }+1=0 \\] + + +# Images are just as easy # + + + ![Nautilus Star](Nautilus_Star.png) + +becomes... + + +# Images are just as easy # + + +![Nautilus Star](Nautilus_Star.png) + + +# Support for a bibliography is also included # + +* MultiMarkdown has support for [BibTeX](http://www.bibtex.org/ "BibTeX"), or + for just including your own citations, so that you can back up your + arguments.[p. 42][#fake] + +* The citation above links to the corresponding entry in the bibliography. + +[#fake]: John Doe. *A Totally Fake Book*. Vanity Press, 2006. + + +# Installation is easy # + +* Download the MultiMarkdown software --- there are installers for Mac OS X + and Windows, and instructions for compiling in Linux. + +* If you want to use LaTeX, install a version appropriate for your operating + system. + +* OpenDocument output doesn't require any special software, but will require + an application capable of opening the document --- LibreOffice, + OpenOffice.org (with the proper plug-in installed), etc. + + +# How do I create a MultiMarkdown document? # + +* A MultiMarkdown is simply a text document that is written in the + MultiMarkdown syntax. You can use any text editor or application you like. + If your editor supports fonts, italics, etc. then be sure to save as a plain + text file (not a .doc, RTF, or other "rich" format). + +* Some applications include built-in support for MultiMarkdown in various + ways. There's a [bundle][] for [TextMate][], and [Scrivener][] includes + MultiMarkdown support. + +[bundle]: http://fletcher.github.com/markdown.tmbundle/ +[TextMate]: http://macromates.com/ +[Scrivener]: http://www.literatureandlatte.com/scrivener.html + + +# Why should I mess with this LaTeX stuff? # + +MultiMarkdown's support for LaTeX is designed to automatically do the "right" +thing in most situations for most people. But if you want to dig in and learn +more, you can customize MMD to create highly tailored documents that suit your +specific needs. If you want high quality typography, LaTeX is the way to go. + +If you already know what LaTeX is, then MultiMarkdown allows you to create +documents without learning all of the complicated LaTeX commands and markup. + + +# How do I create a fancy PDF? # + +If you're using LaTeX, and have the proper software installed it's easy: + +1. Type `mmd2tex filename.txt` + +2. Use `pdflatex`, `xelatex`, or your preferred tool to compile the LaTeX + file into a pdf. + +3. There is no step 3 + + +# Where to learn more # + +* +* +* + + +# By the way... # + +This presentation was, of course, written in MultiMarkdown and processed by +typing `mmd2tex what_is_mmd.txt`. + +It uses the `beamer` XSLT file, and the `keynote-gradient` beamer theme. -- 2.40.0