149ad552dSJiří Techet /*
249ad552dSJiří Techet *
349ad552dSJiří Techet * Copyright (c) 2007-2011, Nick Treleaven
449ad552dSJiří Techet * Copyright (c) 2012, Lex Trotman
549ad552dSJiří Techet * Copyright (c) 2021, Jiri Techet
649ad552dSJiří Techet *
749ad552dSJiří Techet * This source code is released for free distribution under the terms of the
849ad552dSJiří Techet * GNU General Public License version 2 or (at your option) any later version.
949ad552dSJiří Techet *
1049ad552dSJiří Techet * This module contains functions for generating tags for markdown files.
1149ad552dSJiří Techet *
1249ad552dSJiří Techet * This parser was based on the asciidoc parser.
13cfd6b00dSMasatake YAMATO *
14cfd6b00dSMasatake YAMATO * Extended syntax like footnotes is described in
15cfd6b00dSMasatake YAMATO * https://www.markdownguide.org/extended-syntax/
1649ad552dSJiří Techet */
1749ad552dSJiří Techet
1849ad552dSJiří Techet /*
1949ad552dSJiří Techet * INCLUDE FILES
2049ad552dSJiří Techet */
2149ad552dSJiří Techet #include "general.h" /* must always come first */
2249ad552dSJiří Techet
2349ad552dSJiří Techet #include <ctype.h>
2449ad552dSJiří Techet #include <string.h>
2549ad552dSJiří Techet
2649ad552dSJiří Techet #include "debug.h"
2749ad552dSJiří Techet #include "entry.h"
2849ad552dSJiří Techet #include "parse.h"
2949ad552dSJiří Techet #include "read.h"
3049ad552dSJiří Techet #include "vstring.h"
3149ad552dSJiří Techet #include "nestlevel.h"
3249ad552dSJiří Techet #include "routines.h"
3349ad552dSJiří Techet #include "promise.h"
3449ad552dSJiří Techet #include "htable.h"
3549ad552dSJiří Techet
363bbeaff4SMasatake YAMATO #include "markdown.h"
373bbeaff4SMasatake YAMATO
3849ad552dSJiří Techet /*
3949ad552dSJiří Techet * DATA DEFINITIONS
4049ad552dSJiří Techet */
4149ad552dSJiří Techet typedef enum {
4249ad552dSJiří Techet K_CHAPTER = 0,
4349ad552dSJiří Techet K_SECTION,
4449ad552dSJiří Techet K_SUBSECTION,
4549ad552dSJiří Techet K_SUBSUBSECTION,
4649ad552dSJiří Techet K_LEVEL4SECTION,
4749ad552dSJiří Techet K_LEVEL5SECTION,
4849ad552dSJiří Techet K_SECTION_COUNT,
49cfd6b00dSMasatake YAMATO K_FOOTNOTE = K_SECTION_COUNT,
5049ad552dSJiří Techet } markdownKind;
5149ad552dSJiří Techet
5249ad552dSJiří Techet static kindDefinition MarkdownKinds[] = {
5349ad552dSJiří Techet { true, 'c', "chapter", "chapters"},
5449ad552dSJiří Techet { true, 's', "section", "sections" },
5549ad552dSJiří Techet { true, 'S', "subsection", "level 2 sections" },
5649ad552dSJiří Techet { true, 't', "subsubsection", "level 3 sections" },
5749ad552dSJiří Techet { true, 'T', "l4subsection", "level 4 sections" },
5849ad552dSJiří Techet { true, 'u', "l5subsection", "level 5 sections" },
59cfd6b00dSMasatake YAMATO { true, 'n', "footnote", "footnotes" },
6049ad552dSJiří Techet };
6149ad552dSJiří Techet
6249ad552dSJiří Techet static fieldDefinition MarkdownFields [] = {
6349ad552dSJiří Techet {
6449ad552dSJiří Techet .enabled = false,
6549ad552dSJiří Techet .name = "sectionMarker",
6649ad552dSJiří Techet .description = "character used for declaring section(#, ##, =, or -)",
6749ad552dSJiří Techet },
6849ad552dSJiří Techet };
6949ad552dSJiří Techet
7049ad552dSJiří Techet typedef enum {
7149ad552dSJiří Techet F_MARKER,
7249ad552dSJiří Techet } markdownField;
7349ad552dSJiří Techet
7449ad552dSJiří Techet static NestingLevels *nestingLevels = NULL;
7549ad552dSJiří Techet
7649ad552dSJiří Techet /*
7749ad552dSJiří Techet * FUNCTION DEFINITIONS
7849ad552dSJiří Techet */
7949ad552dSJiří Techet
getNestingLevel(const int kind,unsigned long adjustmentWhenPop)80b1bd013cSJiří Techet static NestingLevel *getNestingLevel (const int kind, unsigned long adjustmentWhenPop)
8149ad552dSJiří Techet {
8249ad552dSJiří Techet NestingLevel *nl;
8349ad552dSJiří Techet tagEntryInfo *e;
8449ad552dSJiří Techet unsigned long line = getInputLineNumber ();
8549ad552dSJiří Techet
86b1bd013cSJiří Techet line = (line > adjustmentWhenPop)? (line - adjustmentWhenPop): 0;
8749ad552dSJiří Techet
8849ad552dSJiří Techet while (1)
8949ad552dSJiří Techet {
9049ad552dSJiří Techet nl = nestingLevelsGetCurrent (nestingLevels);
9149ad552dSJiří Techet e = getEntryOfNestingLevel (nl);
9249ad552dSJiří Techet if ((nl && (e == NULL)) || (e && (e->kindIndex >= kind)))
9349ad552dSJiří Techet nestingLevelsPopFull (nestingLevels, HT_UINT_TO_PTR ((unsigned int)line));
9449ad552dSJiří Techet else
9549ad552dSJiří Techet break;
9649ad552dSJiří Techet }
9749ad552dSJiří Techet return nl;
9849ad552dSJiří Techet }
9949ad552dSJiří Techet
1008b9b2540SJiří Techet
makeMarkdownTag(const vString * const name,const int kind,const bool twoLine)101b1bd013cSJiří Techet static int makeMarkdownTag (const vString* const name, const int kind, const bool twoLine)
10249ad552dSJiří Techet {
10349ad552dSJiří Techet int r = CORK_NIL;
10449ad552dSJiří Techet
10549ad552dSJiří Techet if (vStringLength (name) > 0)
10649ad552dSJiří Techet {
107b1bd013cSJiří Techet const NestingLevel *const nl = getNestingLevel (kind, twoLine? 2: 1);
10849ad552dSJiří Techet tagEntryInfo *parent = getEntryOfNestingLevel (nl);
10949ad552dSJiří Techet tagEntryInfo e;
11049ad552dSJiří Techet
11149ad552dSJiří Techet initTagEntry (&e, vStringValue (name), kind);
11249ad552dSJiří Techet
113b1bd013cSJiří Techet if (twoLine)
11449ad552dSJiří Techet {
11549ad552dSJiří Techet /* we want the line before the '---' underline chars */
11649ad552dSJiří Techet const unsigned long line = getInputLineNumber ();
11749ad552dSJiří Techet Assert (line > 0);
11849ad552dSJiří Techet if (line > 0)
11949ad552dSJiří Techet {
12049ad552dSJiří Techet e.lineNumber--;
12149ad552dSJiří Techet e.filePosition = getInputFilePositionForLine (line - 1);
12249ad552dSJiří Techet }
12349ad552dSJiří Techet }
12449ad552dSJiří Techet
12549ad552dSJiří Techet if (parent && (parent->kindIndex < kind))
12649ad552dSJiří Techet e.extensionFields.scopeIndex = nl->corkIndex;
12749ad552dSJiří Techet
12849ad552dSJiří Techet r = makeTagEntry (&e);
12949ad552dSJiří Techet }
13049ad552dSJiří Techet return r;
13149ad552dSJiří Techet }
13249ad552dSJiří Techet
13349ad552dSJiří Techet
makeSectionMarkdownTag(const vString * const name,const int kind,const char * marker)13449ad552dSJiří Techet static int makeSectionMarkdownTag (const vString* const name, const int kind, const char *marker)
13549ad552dSJiří Techet {
13649ad552dSJiří Techet int r = makeMarkdownTag (name, kind, marker[0] != '#');
13749ad552dSJiří Techet attachParserFieldToCorkEntry (r, MarkdownFields [F_MARKER].ftype, marker);
13849ad552dSJiří Techet
13949ad552dSJiří Techet nestingLevelsPush (nestingLevels, r);
14049ad552dSJiří Techet return r;
14149ad552dSJiří Techet }
14249ad552dSJiří Techet
14349ad552dSJiří Techet
getHeading(const int kind,const unsigned char * line,const int lineLen,bool * delimited)144b1bd013cSJiří Techet static vString *getHeading (const int kind, const unsigned char *line,
145b1bd013cSJiří Techet const int lineLen, bool *delimited)
14649ad552dSJiří Techet {
147bd8d8c47SJiří Techet int pos = 0;
14849ad552dSJiří Techet int start = kind + 1;
149b1bd013cSJiří Techet int end = lineLen - 1;
1508b9b2540SJiří Techet vString *name = vStringNew ();
15149ad552dSJiří Techet
15249ad552dSJiří Techet Assert (kind >= 0 && kind < K_SECTION_COUNT);
153b1bd013cSJiří Techet Assert (lineLen > start);
15449ad552dSJiří Techet
1558b9b2540SJiří Techet *delimited = false;
156bd8d8c47SJiří Techet while (isspace (line[pos])) ++pos;
157bd8d8c47SJiří Techet while (line[end] == line[pos] && end - 1 >= 0 && line[end - 1] != '\\')
15849ad552dSJiří Techet {
15949ad552dSJiří Techet --end;
1608b9b2540SJiří Techet *delimited = true;
16149ad552dSJiří Techet }
16249ad552dSJiří Techet while (isspace (line[start])) ++start;
16349ad552dSJiří Techet while (isspace (line[end])) --end;
16449ad552dSJiří Techet
16549ad552dSJiří Techet if (start <= end)
16649ad552dSJiří Techet vStringNCatS (name, (const char*)(&(line[start])), end - start + 1);
16749ad552dSJiří Techet
1688b9b2540SJiří Techet return name;
16949ad552dSJiří Techet }
17049ad552dSJiří Techet
17149ad552dSJiří Techet
getFirstCharPos(const unsigned char * line,int lineLen,bool * indented)172b1bd013cSJiří Techet static int getFirstCharPos (const unsigned char *line, int lineLen, bool *indented)
173aae06182SJiří Techet {
174aae06182SJiří Techet int indent = 0;
175d0d780efSJiří Techet int i;
176b1bd013cSJiří Techet for (i = 0; i < lineLen && isspace (line[i]); i++)
177aae06182SJiří Techet indent += line[i] == '\t' ? 4 : 1;
178d0d780efSJiří Techet *indented = indent >= 4;
179d0d780efSJiří Techet return i;
180aae06182SJiří Techet }
181aae06182SJiří Techet
182aae06182SJiří Techet
fillEndField(NestingLevel * nl,void * ctxData)18349ad552dSJiří Techet static void fillEndField (NestingLevel *nl, void *ctxData)
18449ad552dSJiří Techet {
18549ad552dSJiří Techet tagEntryInfo *e = getEntryOfNestingLevel (nl);
18649ad552dSJiří Techet if (e)
18749ad552dSJiří Techet {
18849ad552dSJiří Techet unsigned long line = (unsigned long)(HT_PTR_TO_UINT (ctxData));
18949ad552dSJiří Techet e->extensionFields.endLine = line;
19049ad552dSJiří Techet }
19149ad552dSJiří Techet }
19249ad552dSJiří Techet
getFootnoteMaybe(const char * line)193cfd6b00dSMasatake YAMATO static void getFootnoteMaybe (const char *line)
194cfd6b00dSMasatake YAMATO {
195cfd6b00dSMasatake YAMATO const char *start = strstr (line, "[^");
196cfd6b00dSMasatake YAMATO const char *end = start? strstr(start + 2, "]:"): NULL;
197cfd6b00dSMasatake YAMATO
198cfd6b00dSMasatake YAMATO if (! (start && end))
199cfd6b00dSMasatake YAMATO return;
200cfd6b00dSMasatake YAMATO if (! (end > (start + 2)))
201cfd6b00dSMasatake YAMATO return;
202cfd6b00dSMasatake YAMATO
203cfd6b00dSMasatake YAMATO vString * footnote = vStringNewNInit (start + 2, end - (start + 2));
204cfd6b00dSMasatake YAMATO const NestingLevel *const nl = nestingLevelsGetCurrent (nestingLevels);
205cfd6b00dSMasatake YAMATO tagEntryInfo e;
206cfd6b00dSMasatake YAMATO
207cfd6b00dSMasatake YAMATO initTagEntry (&e, vStringValue (footnote), K_FOOTNOTE);
208cfd6b00dSMasatake YAMATO if (nl)
209cfd6b00dSMasatake YAMATO e.extensionFields.scopeIndex = nl->corkIndex;
210cfd6b00dSMasatake YAMATO makeTagEntry (&e);
211cfd6b00dSMasatake YAMATO
212cfd6b00dSMasatake YAMATO vStringDelete (footnote);
213cfd6b00dSMasatake YAMATO }
2148b9b2540SJiří Techet
extractLanguageForCodeBlock(const char * langMarker,vString * codeLang)2153bbeaff4SMasatake YAMATO static bool extractLanguageForCodeBlock (const char *langMarker,
2163bbeaff4SMasatake YAMATO vString *codeLang)
2173bbeaff4SMasatake YAMATO {
2183bbeaff4SMasatake YAMATO subparser *s;
2193bbeaff4SMasatake YAMATO bool r = false;
2203bbeaff4SMasatake YAMATO
2213bbeaff4SMasatake YAMATO foreachSubparser (s, false)
2223bbeaff4SMasatake YAMATO {
2233bbeaff4SMasatake YAMATO markdownSubparser *m = (markdownSubparser *)s;
2243bbeaff4SMasatake YAMATO enterSubparser(s);
2253bbeaff4SMasatake YAMATO if (m->extractLanguageForCodeBlock)
2263bbeaff4SMasatake YAMATO r = m->extractLanguageForCodeBlock (m, langMarker, codeLang);
2273bbeaff4SMasatake YAMATO leaveSubparser();
2283bbeaff4SMasatake YAMATO if (r)
2293bbeaff4SMasatake YAMATO break;
2303bbeaff4SMasatake YAMATO }
2313bbeaff4SMasatake YAMATO
2323bbeaff4SMasatake YAMATO return r;
2333bbeaff4SMasatake YAMATO }
2343bbeaff4SMasatake YAMATO
findMarkdownTags(void)23549ad552dSJiří Techet static void findMarkdownTags (void)
23649ad552dSJiří Techet {
237b1bd013cSJiří Techet vString *prevLine = vStringNew ();
23849ad552dSJiří Techet vString *codeLang = vStringNew ();
23949ad552dSJiří Techet const unsigned char *line;
240b1bd013cSJiří Techet char inCodeChar = 0;
24149ad552dSJiří Techet long startSourceLineNumber = 0;
24249ad552dSJiří Techet long startLineNumber = 0;
24324605713SJiří Techet bool inPreambule = false;
24478320f2bSJiří Techet bool inComment = false;
24549ad552dSJiří Techet
2463bbeaff4SMasatake YAMATO subparser *sub = getSubparserRunningBaseparser();
2473bbeaff4SMasatake YAMATO if (sub)
2483bbeaff4SMasatake YAMATO chooseExclusiveSubparser (sub, NULL);
2493bbeaff4SMasatake YAMATO
25049ad552dSJiří Techet nestingLevels = nestingLevelsNewFull (0, fillEndField);
25149ad552dSJiří Techet
25249ad552dSJiří Techet while ((line = readLineFromInputFile ()) != NULL)
25349ad552dSJiří Techet {
254b1bd013cSJiří Techet int lineLen = strlen ((const char*) line);
255b1bd013cSJiří Techet bool lineProcessed = false;
256d0d780efSJiří Techet bool indented;
257b1bd013cSJiří Techet int pos = getFirstCharPos (line, lineLen, &indented);
2588d4de3bdSMasatake YAMATO const int lineNum = getInputLineNumber ();
25924605713SJiří Techet
26024605713SJiří Techet if (lineNum == 1 || inPreambule)
26124605713SJiří Techet {
26224605713SJiří Techet if (line[pos] == '-' && line[pos + 1] == '-' && line[pos + 2] == '-')
263*53286604SMasatake YAMATO {
264*53286604SMasatake YAMATO if (inPreambule)
265*53286604SMasatake YAMATO {
266*53286604SMasatake YAMATO long endLineNumber = lineNum;
267*53286604SMasatake YAMATO if (startLineNumber < endLineNumber)
268*53286604SMasatake YAMATO makePromise ("FrontMatter", startLineNumber, 0,
269*53286604SMasatake YAMATO endLineNumber, 0, startSourceLineNumber);
270*53286604SMasatake YAMATO }
271*53286604SMasatake YAMATO else
272*53286604SMasatake YAMATO startSourceLineNumber = startLineNumber = lineNum;
27324605713SJiří Techet inPreambule = !inPreambule;
27424605713SJiří Techet }
275*53286604SMasatake YAMATO }
27624605713SJiří Techet
27724605713SJiří Techet if (inPreambule)
27824605713SJiří Techet continue;
27949ad552dSJiří Techet
28035c6034aSJiří Techet /* fenced code block */
28135c6034aSJiří Techet if (line[pos] == '`' || line[pos] == '~')
28249ad552dSJiří Techet {
28335c6034aSJiří Techet char c = line[pos];
284b1bd013cSJiří Techet char otherC = c == '`' ? '~' : '`';
285b1bd013cSJiří Techet int nSame;
286b1bd013cSJiří Techet for (nSame = 1; line[nSame] == line[pos]; ++nSame);
28749ad552dSJiří Techet
288b1bd013cSJiří Techet if (inCodeChar != otherC && nSame >= 3)
28949ad552dSJiří Techet {
290b1bd013cSJiří Techet inCodeChar = inCodeChar ? 0 : c;
291b1bd013cSJiří Techet if (inCodeChar == c && strstr ((const char *)(line + pos + nSame), "```") != NULL)
292b1bd013cSJiří Techet inCodeChar = 0;
293b1bd013cSJiří Techet else if (inCodeChar)
29449ad552dSJiří Techet {
2953bbeaff4SMasatake YAMATO const char *langMarker = (const char *)(line + pos + nSame);
2968d4de3bdSMasatake YAMATO startLineNumber = startSourceLineNumber = lineNum + 1;
2973bbeaff4SMasatake YAMATO
2983bbeaff4SMasatake YAMATO vStringClear (codeLang);
2993bbeaff4SMasatake YAMATO if (! extractLanguageForCodeBlock (langMarker, codeLang))
3003bbeaff4SMasatake YAMATO {
3013bbeaff4SMasatake YAMATO vStringCopyS (codeLang, langMarker);
30249ad552dSJiří Techet vStringStripLeading (codeLang);
30349ad552dSJiří Techet vStringStripTrailing (codeLang);
30449ad552dSJiří Techet }
3053bbeaff4SMasatake YAMATO }
30649ad552dSJiří Techet else
30749ad552dSJiří Techet {
3088d4de3bdSMasatake YAMATO long endLineNumber = lineNum;
3098d4de3bdSMasatake YAMATO if (vStringLength (codeLang) > 0
3108d4de3bdSMasatake YAMATO && startLineNumber < endLineNumber)
31149ad552dSJiří Techet makePromise (vStringValue (codeLang), startLineNumber, 0,
31249ad552dSJiří Techet endLineNumber, 0, startSourceLineNumber);
31349ad552dSJiří Techet }
3148b9b2540SJiří Techet
315b1bd013cSJiří Techet lineProcessed = true;
31649ad552dSJiří Techet }
31749ad552dSJiří Techet }
31878320f2bSJiří Techet /* XML comment start */
31978320f2bSJiří Techet else if (lineLen >= pos + 4 && line[pos] == '<' && line[pos + 1] == '!' &&
32078320f2bSJiří Techet line[pos + 2] == '-' && line[pos + 3] == '-')
32178320f2bSJiří Techet {
32278320f2bSJiří Techet if (strstr ((const char *)(line + pos + 4), "-->") == NULL)
32378320f2bSJiří Techet inComment = true;
32478320f2bSJiří Techet lineProcessed = true;
32578320f2bSJiří Techet }
32678320f2bSJiří Techet /* XML comment end */
32778320f2bSJiří Techet else if (inComment && strstr ((const char *)(line + pos), "-->"))
32878320f2bSJiří Techet {
32978320f2bSJiří Techet inComment = false;
33078320f2bSJiří Techet lineProcessed = true;
33178320f2bSJiří Techet }
33249ad552dSJiří Techet
33378320f2bSJiří Techet /* code block or comment */
33478320f2bSJiří Techet if (inCodeChar || inComment)
335b1bd013cSJiří Techet lineProcessed = true;
33649ad552dSJiří Techet
3378b9b2540SJiří Techet /* code block using indent */
338d0d780efSJiří Techet else if (indented)
339b1bd013cSJiří Techet lineProcessed = true;
34049ad552dSJiří Techet
3418b9b2540SJiří Techet /* if it's a title underline, or a delimited block marking character */
3423ec4209aSJiří Techet else if (line[pos] == '=' || line[pos] == '-' || line[pos] == '#' || line[pos] == '>')
34349ad552dSJiří Techet {
344b1bd013cSJiří Techet int nSame;
345b1bd013cSJiří Techet for (nSame = 1; line[nSame] == line[pos]; ++nSame);
34649ad552dSJiří Techet
3473ec4209aSJiří Techet /* quote */
3483ec4209aSJiří Techet if (line[pos] == '>')
349b1bd013cSJiří Techet ; /* just to make sure lineProcessed = true so it won't be in a heading */
35049ad552dSJiří Techet /* is it a two line title */
3513ec4209aSJiří Techet else if (line[pos] == '=' || line[pos] == '-')
35249ad552dSJiří Techet {
353d0d780efSJiří Techet char marker[2] = { line[pos], '\0' };
354d0d780efSJiří Techet int kind = line[pos] == '=' ? K_CHAPTER : K_SECTION;
355b1bd013cSJiří Techet bool whitespaceTerminated = true;
35687d0d57aSJiří Techet
357b1bd013cSJiří Techet for (int i = pos + nSame; i < lineLen; i++)
35887d0d57aSJiří Techet {
35987d0d57aSJiří Techet if (!isspace (line[i]))
36087d0d57aSJiří Techet {
361b1bd013cSJiří Techet whitespaceTerminated = false;
36287d0d57aSJiří Techet break;
36387d0d57aSJiří Techet }
36487d0d57aSJiří Techet }
36587d0d57aSJiří Techet
366b1bd013cSJiří Techet vStringStripLeading (prevLine);
367b1bd013cSJiří Techet vStringStripTrailing (prevLine);
368b1bd013cSJiří Techet if (whitespaceTerminated && vStringLength (prevLine) > 0)
369b1bd013cSJiří Techet makeSectionMarkdownTag (prevLine, kind, marker);
37049ad552dSJiří Techet }
37149ad552dSJiří Techet /* otherwise is it a one line title */
372b1bd013cSJiří Techet else if (line[pos] == '#' && nSame <= K_SECTION_COUNT && isspace (line[nSame]))
37349ad552dSJiří Techet {
374b1bd013cSJiří Techet int kind = nSame - 1;
3758b9b2540SJiří Techet bool delimited = false;
376b1bd013cSJiří Techet vString *name = getHeading (kind, line, lineLen, &delimited);
3778b9b2540SJiří Techet if (vStringLength (name) > 0)
37849ad552dSJiří Techet makeSectionMarkdownTag (name, kind, delimited ? "##" : "#");
37949ad552dSJiří Techet vStringDelete (name);
3808b9b2540SJiří Techet }
3818b9b2540SJiří Techet
382b1bd013cSJiří Techet lineProcessed = true;
3838b9b2540SJiří Techet }
3848b9b2540SJiří Techet
385b1bd013cSJiří Techet vStringClear (prevLine);
386b1bd013cSJiří Techet if (!lineProcessed)
387cfd6b00dSMasatake YAMATO {
388cfd6b00dSMasatake YAMATO getFootnoteMaybe ((const char *)line);
389b1bd013cSJiří Techet vStringCatS (prevLine, (const char*) line);
3908b9b2540SJiří Techet }
391cfd6b00dSMasatake YAMATO }
392b1bd013cSJiří Techet vStringDelete (prevLine);
39349ad552dSJiří Techet vStringDelete (codeLang);
39449ad552dSJiří Techet {
39549ad552dSJiří Techet unsigned int line = (unsigned int)getInputLineNumber ();
39649ad552dSJiří Techet nestingLevelsFreeFull (nestingLevels, HT_UINT_TO_PTR (line));
39749ad552dSJiří Techet }
39849ad552dSJiří Techet }
39949ad552dSJiří Techet
MarkdownParser(void)40049ad552dSJiří Techet extern parserDefinition* MarkdownParser (void)
40149ad552dSJiří Techet {
40249ad552dSJiří Techet parserDefinition* const def = parserNew ("Markdown");
40349ad552dSJiří Techet static const char *const extensions [] = { "md", "markdown", NULL };
40449ad552dSJiří Techet
40549ad552dSJiří Techet def->enabled = true;
40649ad552dSJiří Techet def->extensions = extensions;
40749ad552dSJiří Techet def->useCork = CORK_QUEUE;
40849ad552dSJiří Techet def->kindTable = MarkdownKinds;
40949ad552dSJiří Techet def->kindCount = ARRAY_SIZE (MarkdownKinds);
41049ad552dSJiří Techet def->fieldTable = MarkdownFields;
41149ad552dSJiří Techet def->fieldCount = ARRAY_SIZE (MarkdownFields);
41249ad552dSJiří Techet def->defaultScopeSeparator = "\"\"";
41349ad552dSJiří Techet def->parser = findMarkdownTags;
41449ad552dSJiří Techet
415*53286604SMasatake YAMATO /*
416*53286604SMasatake YAMATO * This setting (useMemoryStreamInput) is for running
417*53286604SMasatake YAMATO * Yaml parser from YamlFrontMatter as subparser.
418*53286604SMasatake YAMATO * YamlFrontMatter is run from FrontMatter as a gust parser.
419*53286604SMasatake YAMATO * FrontMatter is run from Markdown as a guest parser.
420*53286604SMasatake YAMATO * This stacked structure hits the limitation of the main
421*53286604SMasatake YAMATO * part: subparser's requirement for memory based input stream
422*53286604SMasatake YAMATO * is not propagated to the main part.
423*53286604SMasatake YAMATO *
424*53286604SMasatake YAMATO * TODO: instead of setting useMemoryStreamInput here, we
425*53286604SMasatake YAMATO * should remove the limitation.
426*53286604SMasatake YAMATO */
427*53286604SMasatake YAMATO def->useMemoryStreamInput = true;
428*53286604SMasatake YAMATO
42949ad552dSJiří Techet return def;
43049ad552dSJiří Techet }
431