139 lines
3.3 KiB
Nim
139 lines
3.3 KiB
Nim
import std/[
|
|
collections/sequtils,
|
|
sugar,
|
|
]
|
|
import fp/[
|
|
option,
|
|
resultM,
|
|
]
|
|
import ./org_types
|
|
import ./org_builder_api
|
|
import ./org_builder_link
|
|
import ./org_builder_inline_text
|
|
import ../parser/parser
|
|
import ../utils/fp
|
|
|
|
import fusion/matching
|
|
{.experimental: "caseStmtMacros".}
|
|
|
|
# let lineTokenizer = (builder: OrgInlineBuilder) => tryTokenize(
|
|
# builder = builder,
|
|
# builderFns = styledTextTokenizers,
|
|
# defaultTokenizerFn = tryTokenizeRawText,
|
|
# )
|
|
|
|
# OrgDocucment
|
|
|
|
# -> Seq [Builder -> Builder]
|
|
|
|
# One of OrgBlock
|
|
|
|
# @[
|
|
|
|
# OrgBuilderResult -> OrgBuilderResult
|
|
# ]
|
|
# with default OrgBuilder -> OrgBuilder
|
|
# until Eol
|
|
|
|
let lineParser = anyUntil(newlineOrEol)
|
|
|
|
let listTypesParser = choice(@[
|
|
ch('-'),
|
|
ch('+'),
|
|
choice(@[letter, digit]) + choice(@[ch('.'), ch(')')]),
|
|
])
|
|
|
|
let listStartParser = manyUntil(space, listTypesParser)
|
|
let listTypeParser = listTypesParser + ignore(space)
|
|
let listContentParser = anyUntil(newlineOrEol) + ignore(newlineOrEol)
|
|
|
|
let buildListItem = proc(builder: OrgBuilder): OrgBuilderResult {.closure.} =
|
|
let (parser, tree) = builder
|
|
|
|
let beforeSpaces = ParserResult.ok(parser)
|
|
.flatMap(listStartParser)
|
|
.map(flattenTokens)
|
|
|
|
let listType = beforeSpaces
|
|
.map(emptyTokens)
|
|
.flatMap(listTypeParser)
|
|
.map(flattenTokens)
|
|
|
|
let listContent = listType
|
|
.map(emptyTokens)
|
|
.flatMap(listContentParser)
|
|
.map(flattenTokens)
|
|
|
|
case (beforeSpaces, listType, listContent):
|
|
of (Some(@space), Some(@symbol), Some(@content)):
|
|
let treeResult = tree &
|
|
OrgBlock(
|
|
kind: orgList,
|
|
listIndentation: 1,
|
|
listBulletType: '-',
|
|
listContent: tryTokenizeInline(content.tokens.tokensToString()).unsafeGet().tree
|
|
)
|
|
|
|
OrgBuilderResult.ok(OrgBuilder((
|
|
parser: content,
|
|
tree: treeResult,
|
|
)))
|
|
else: OrgBuilderResult.err(OrgBuilderError(
|
|
kind: parserError,
|
|
parser: listContent,
|
|
tree: tree,
|
|
))
|
|
|
|
proc buildParagraph*(
|
|
builder: OrgBuilder,
|
|
builderFns: seq[proc (builder: OrgBuilder): OrgBuilderResult],
|
|
stopAtParserFn = endOfStream,
|
|
): OrgBuilderResult =
|
|
|
|
var builderAcc: OrgBuilderResult = OrgBuilderResult.ok(builder)
|
|
|
|
while builderAcc.isOk() and builderAcc.tryParserResult(stopAtParserFn).isErr():
|
|
var found = false
|
|
|
|
for builderFn in builderFns:
|
|
# let (builderFn) = fn
|
|
let builderResult: OrgBuilderResult = builderAcc.flatMap(builderFn)
|
|
|
|
if builderResult.isOk():
|
|
found = true
|
|
builderAcc = builderResult
|
|
break
|
|
|
|
if not found:
|
|
builderAcc
|
|
.flatMap((builder: OrgBuilder) => tryTokenize(
|
|
builder = builder,
|
|
builderFns = styledTextTokenizers,
|
|
defaultTokenizerFn = tryTokenizeRawText,
|
|
))
|
|
.fold(
|
|
OrgInlineBuilder
|
|
)
|
|
|
|
|
|
builderAcc = OrgBuilderResult.err(OrgBuilderError(
|
|
kind: builderError,
|
|
parser: builderAcc.fold(
|
|
(err: OrgBuilderError) => err.parser,
|
|
(builder: OrgBuilder) => ParserResult.ok(builder.parser),
|
|
),
|
|
tree: builder.tree,
|
|
))
|
|
break
|
|
|
|
builderAcc
|
|
|
|
let paragraphBuilders: seq[proc (builder: OrgBuilder): OrgBuilderResult] = @[buildListItem]
|
|
|
|
when isMainModule:
|
|
block testParsers:
|
|
let test = initOrgBuilder("""- List item
|
|
1. List item
|
|
random stuff""").flatMap((builder: OrgBuilder) => builder.buildParagraph(paragraphBuilders))
|
|
echo test
|